summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/cpu/st9/st9dasm.cpp1373
-rw-r--r--src/devices/cpu/st9/st9dasm.h90
-rw-r--r--src/tools/unidasm.cpp3
3 files changed, 1466 insertions, 0 deletions
diff --git a/src/devices/cpu/st9/st9dasm.cpp b/src/devices/cpu/st9/st9dasm.cpp
new file mode 100644
index 00000000000..fa8c2a6abf5
--- /dev/null
+++ b/src/devices/cpu/st9/st9dasm.cpp
@@ -0,0 +1,1373 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/***************************************************************************
+
+ SGS-Thomson/STMicroelectronics ST9 Family disassembler
+
+ This architecture loosely resembles that of Zilog's Super8 and Z8, but
+ adds many 16-bit operations and indirect addressing modes. Instructions
+ listed as ALD and ALDW in opcode maps are actually mode prefixes
+ for common ALU instructions.
+
+ ST9+ extends the program space to 22 bits by using segmentation and
+ also adds several instructions to facilitate stack frame linkage.
+
+ ETRAP and ERET are listed in the ST9+ Opcode Map but are otherwise
+ undocumented. These instructions were likely reserved for special
+ debugging tools.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "st9dasm.h"
+
+st9_disassembler::st9_disassembler()
+ : util::disasm_interface()
+{
+}
+
+u32 st9_disassembler::opcode_alignment() const
+{
+ return 1;
+}
+
+u32 st9p_disassembler::interface_flags() const
+{
+ return PAGED;
+}
+
+u32 st9p_disassembler::page_address_bits() const
+{
+ return 16;
+}
+
+namespace {
+
+const char *const s_ald[16] =
+{
+ "or", "and",
+ "sbc", "adc",
+ "add", "sub",
+ "xor", nullptr,
+ "tcm", "cp",
+ "tm", nullptr,
+ nullptr, nullptr,
+ nullptr, "ld"
+};
+
+const char *const s_aldw[16] =
+{
+ "orw", "andw",
+ "sbcw", "adcw",
+ "addw", "subw",
+ "xorw", nullptr,
+ "tcmw", "cpw",
+ "tmw", nullptr,
+ nullptr, nullptr,
+ nullptr, "ldw"
+};
+
+const char *const s_unary_inst[16] =
+{
+ nullptr, nullptr,
+ "popu", "pushu",
+ "dec", "inc",
+ nullptr, "da",
+ "cpl", "clr",
+ "rol", "rlc",
+ "ror", "rrc",
+ "sra", "swap"
+};
+
+const char *const s_cc[16] =
+{
+ "f", "lt", "le", "ule", "ov", "mi", "eq", "c",
+ "", "ge", "gt", "ugt", "nov", "pl", "ne", "nc"
+};
+
+const char *const s_group_e[16] =
+{
+ "P0DR", "P1DR",
+ "P2DR", "P3DR",
+ "P4DR", "P5DR",
+ "CICR", "FLAGR",
+ "RP0R", "RP1R",
+ "PPR", "MODER",
+ "USPHR", "USPLR",
+ "SSPHR", "SSPLR"
+};
+
+} // anonymous namespace
+
+void st9_disassembler::format_dir(std::ostream &stream, u8 r) const
+{
+ if ((r & 0xf0) == 0xd0)
+ util::stream_format(stream, "r%d", r & 0x0f);
+ else if ((r & 0xf0) == 0xe0)
+ stream << s_group_e[r & 0x0f]; // R224-R239
+ else
+ util::stream_format(stream, "R%02X", r);
+}
+
+void st9_disassembler::format_dirw(std::ostream &stream, u8 rr) const
+{
+ if ((rr & 0xf0) == 0xd0)
+ util::stream_format(stream, "rr%d", rr & 0x0f);
+ else if (rr == 0xee)
+ stream << "SSPR"; // RR238
+ else if (rr == 0xec)
+ stream << "USPR"; // RR236
+ else if (rr == 0xe8)
+ stream << "RPR";
+ else
+ util::stream_format(stream, "RR%02X", rr);
+}
+
+void st9_disassembler::format_imm(std::ostream &stream, u8 n) const
+{
+ stream << '#';
+ if (n >= 0xa0)
+ stream << '0';
+ util::stream_format(stream, "%02Xh", n);
+}
+
+void st9_disassembler::format_immw(std::ostream &stream, u16 nn) const
+{
+ stream << '#';
+ if (nn >= 0xa000)
+ stream << '0';
+ util::stream_format(stream, "%04Xh", nn);
+}
+
+void st9_disassembler::format_disp(std::ostream &stream, s8 n) const
+{
+ util::stream_format(stream, "%d", n);
+}
+
+void st9_disassembler::format_dispw(std::ostream &stream, u16 nn) const
+{
+ if (nn >= 0xa000)
+ stream << '0';
+ util::stream_format(stream, "%04Xh", nn);
+}
+
+void st9_disassembler::format_label(std::ostream &stream, u16 nn) const
+{
+ if (nn >= 0xa000)
+ stream << '0';
+ util::stream_format(stream, "%04Xh", nn);
+}
+
+offs_t st9_disassembler::dasm_unknown(std::ostream &stream, u8 opc) const
+{
+ util::stream_format(stream, "%-8s", ".byte");
+ if (opc >= 0xa0)
+ stream << '0';
+ util::stream_format(stream, "%02Xh", opc);
+ return 1 | SUPPORTED;
+}
+
+offs_t st9_disassembler::dasm_06(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const aldw = s_aldw[byte1 >> 4];
+ if (aldw != nullptr)
+ {
+ util::stream_format(stream, "%-8s", aldw);
+ if (BIT(byte1, 0))
+ {
+ format_disp(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ stream << ',';
+ format_immw(stream, opcodes.r8(pc + 3));
+ return 5 | SUPPORTED;
+ }
+ else
+ {
+ format_dispw(stream, opcodes.r16(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ stream << ',';
+ format_immw(stream, opcodes.r8(pc + 4));
+ return 6 | SUPPORTED;
+ }
+ }
+ else
+ return dasm_unknown(stream, 0x06);
+}
+
+offs_t st9_disassembler::dasm_0f(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 4))
+ {
+ const u8 byte2 = opcodes.r8(pc + 2);
+ util::stream_format(stream, "%-8sr%d.%d,r%d.%s%d", "bor", byte1 & 0x0f, byte1 >> 5, byte2 & 0x0f, BIT(byte2, 4) ? "!" : "", byte2 >> 5);
+ return 3 | SUPPORTED;
+ }
+ else
+ {
+ util::stream_format(stream, "%-8sr%d.%d", "bset", byte1 & 0x0f, byte1 >> 5);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_1f(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 4))
+ {
+ const u8 byte2 = opcodes.r8(pc + 2);
+ util::stream_format(stream, "%-8sr%d.%d,r%d.%s%d", "band", byte1 & 0x0f, byte1 >> 5, byte2 & 0x0f, BIT(byte2, 4) ? "!" : "", byte2 >> 5);
+ return 3 | SUPPORTED;
+ }
+ else
+ {
+ util::stream_format(stream, "%-8sr%d.%d", "bres", byte1 & 0x0f, byte1 >> 5);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_26(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ if (BIT(byte1, 0))
+ {
+ format_disp(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ stream << ',';
+ format_dir(stream, opcodes.r8(pc + 3));
+ return 4 | SUPPORTED;
+ }
+ else
+ {
+ format_dispw(stream, opcodes.r16(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ stream << ',';
+ format_dir(stream, opcodes.r8(pc + 4));
+ return 5 | SUPPORTED;
+ }
+ }
+ else
+ return dasm_unknown(stream, 0x26);
+}
+
+offs_t st9_disassembler::dasm_2f(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (!BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", "sraw");
+ format_dirw(stream, byte1);
+ return 2 | SUPPORTED;
+ }
+ else if (s_ald[byte1 >> 4] != nullptr)
+ {
+ util::stream_format(stream, "%-8s", s_ald[byte1 >> 4]);
+ format_label(stream, opcodes.r16(pc + 3));
+ stream << ',';
+ format_imm(stream, opcodes.r8(pc + 2));
+ return 5 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x2f);
+}
+
+offs_t st9_disassembler::dasm_36(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (!BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", "rrcw");
+ format_dirw(stream, byte1);
+ return 2 | SUPPORTED;
+ }
+ else if (s_aldw[byte1 >> 4] != nullptr)
+ {
+ util::stream_format(stream, "%-8s", s_aldw[byte1 >> 4]);
+ format_label(stream, opcodes.r16(pc + 4));
+ stream << ',';
+ format_immw(stream, opcodes.r16(pc + 2));
+ return 6 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x36);
+}
+
+offs_t st9_disassembler::dasm_3f(std::ostream &stream, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ return dasm_unknown(stream, 0x3f);
+}
+
+offs_t st9p_disassembler::dasm_3f(std::ostream &stream, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const u8 byte1 = opcodes.r8(pc + 1);
+ if (BIT(byte1, 6))
+ {
+ util::stream_format(stream, "%-8s%02Xh,", BIT(byte1, 7) ? "jps" : "calls", byte1 & 0x3f);
+ format_label(stream, opcodes.r16(pc + 2));
+ return 4 | (BIT(byte1, 7) ? 0 : STEP_OVER) | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x3f);
+}
+
+offs_t st9_disassembler::dasm_60(std::ostream &stream, u8 byte1, u8 byte2) const
+{
+ const char *const ald = BIT(byte1, 4) ? s_ald[byte2 >> 4] : s_aldw[byte2 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ if (BIT(byte1, 0))
+ util::stream_format(stream, "rr%d(rr%d),", (byte1 & 0xe0) >> 4, byte1 & 0x0e);
+ util::stream_format(stream, "%s%d", BIT(byte1, 4) ? "r" : "rr", byte2 & 0x0f);
+ if (!BIT(byte1, 0))
+ util::stream_format(stream, ",rr%d(rr%d)", (byte1 & 0xe0) >> 4, byte1 & 0x0e);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x60);
+}
+
+offs_t st9_disassembler::dasm_6f(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 4))
+ {
+ const u8 byte2 = opcodes.r8(pc + 2);
+ util::stream_format(stream, "%-8sr%d.%d,r%d.%s%d", "bxor", byte1 & 0x0f, byte1 >> 5, byte2 & 0x0f, BIT(byte2, 4) ? "!" : "", byte2 >> 5);
+ return 3 | SUPPORTED;
+ }
+ else
+ {
+ util::stream_format(stream, "%-8sr%d.%d", "bcpl", byte1 & 0x0f, byte1 >> 5);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_72(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ if (!BIT(byte1, 0))
+ util::stream_format(stream, "(rr%d),", byte1 & 0x0e);
+ format_dir(stream, opcodes.r8(pc + 2));
+ if (BIT(byte1, 0))
+ util::stream_format(stream, ",(rr%d)", byte1 & 0x0e);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x72);
+}
+
+offs_t st9_disassembler::dasm_73(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ if (ald != nullptr && !BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s(", ald);
+ format_dirw(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "),(rr%d)", byte1 & 0x0e);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x73);
+}
+
+offs_t st9p_disassembler::dasm_73(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if ((byte1 & 0x71) == 0x41)
+ {
+ util::stream_format(stream, "%-8s(", BIT(byte1, 7) ? "jps" : "calls");
+ format_dirw(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "),(rr%d)", byte1 & 0x0e);
+ return 3 | (BIT(byte1, 7) ? 0 : STEP_OVER) | SUPPORTED;
+ }
+ else
+ return st9_disassembler::dasm_73(stream, byte1, pc, opcodes);
+}
+
+offs_t st9_disassembler::dasm_74(std::ostream &stream, u8 byte1) const
+{
+ if (BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s(", "call");
+ format_dirw(stream, byte1 & 0xfe);
+ stream << ')';
+ return 2 | STEP_OVER | SUPPORTED;
+ }
+ else
+ {
+ util::stream_format(stream, "%-8s", "pushw");
+ format_dirw(stream, byte1);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_75(std::ostream &stream, u8 byte1) const
+{
+ if (BIT(byte1, 0))
+ return dasm_unknown(stream, 0x75);
+ else
+ {
+ util::stream_format(stream, "%-8s", "popw");
+ format_dirw(stream, byte1);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9p_disassembler::dasm_75(std::ostream &stream, u8 byte1) const
+{
+ if (BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", "unlink");
+ format_dirw(stream, byte1 & 0xfe);
+ return 2 | SUPPORTED;
+ }
+ else
+ return st9_disassembler::dasm_75(stream, byte1);
+}
+
+offs_t st9_disassembler::dasm_7e(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const aldw = s_aldw[byte1 >> 4];
+ if (aldw != nullptr && !BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", aldw);
+ format_dirw(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, ",(rr%d)", byte1 & 0x0e);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x7e);
+}
+
+offs_t st9_disassembler::dasm_7f(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ if (BIT(byte1, 0))
+ {
+ format_dir(stream, opcodes.r8(pc + 3));
+ stream << ',';
+ format_disp(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ return 4 | SUPPORTED;
+ }
+ else
+ {
+ format_dir(stream, opcodes.r8(pc + 4));
+ stream << ',';
+ format_dispw(stream, opcodes.r16(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ return 5 | SUPPORTED;
+ }
+ }
+ else
+ return dasm_unknown(stream, 0x7f);
+}
+
+offs_t st9_disassembler::dasm_86(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const aldw = s_aldw[byte1 >> 4];
+ if (aldw != nullptr)
+ {
+ util::stream_format(stream, "%-8s", aldw);
+ if (BIT(byte1, 0))
+ {
+ const u8 byte3 = opcodes.r8(pc + 3);
+ if (!BIT(byte3, 0))
+ {
+ format_dirw(stream, byte3);
+ stream << ',';
+ }
+ format_disp(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ if (BIT(byte3, 0))
+ {
+ stream << ',';
+ format_dirw(stream, byte3 & 0xfe);
+ }
+ return 4 | SUPPORTED;
+ }
+ else
+ {
+ const u8 byte4 = opcodes.r8(pc + 4);
+ if (!BIT(byte4, 0))
+ {
+ format_dirw(stream, byte4);
+ stream << ',';
+ }
+ format_dispw(stream, opcodes.r16(pc + 2));
+ util::stream_format(stream, "(rr%d)", byte1 & 0x0e);
+ if (BIT(byte4, 0))
+ {
+ stream << ',';
+ format_dirw(stream, byte4 & 0xfe);
+ }
+ return 5 | SUPPORTED;
+ }
+ }
+ else
+ return dasm_unknown(stream, 0x86);
+}
+
+offs_t st9_disassembler::dasm_8f(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (!BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", "rlcw");
+ format_dirw(stream, byte1);
+ return 2 | SUPPORTED;
+ }
+ else switch (byte1)
+ {
+ case 0x01: case 0x03:
+ {
+ const u8 byte2 = opcodes.r8(pc + 2);
+ util::stream_format(stream, "%-8s", BIT(byte1, 1) ? "peau" : "pea");
+ if (BIT(byte2, 0))
+ format_dispw(stream, opcodes.r16(pc + 3));
+ else
+ format_disp(stream, opcodes.r8(pc + 3));
+ stream << '(';
+ format_dirw(stream, byte2 & 0xfe);
+ stream << ')';
+ return (BIT(byte2, 0) ? 5 : 4) | SUPPORTED;
+ }
+
+ case 0xc1: case 0xc3:
+ util::stream_format(stream, "%-8s", BIT(byte1, 1) ? "pushuw" : "pushw");
+ format_immw(stream, opcodes.r8(pc + 2));
+ return 4 | SUPPORTED;
+
+ case 0xf1: case 0xf3:
+ util::stream_format(stream, "%-8s", BIT(byte1, 1) ? "pushu" : "push");
+ format_imm(stream, opcodes.r8(pc + 2));
+ return 3 | SUPPORTED;
+
+ default:
+ return dasm_unknown(stream, 0x8f);
+ }
+}
+
+offs_t st9_disassembler::dasm_96(std::ostream &stream, u8 byte1, u8 byte2) const
+{
+ const char *const aldw = s_aldw[byte2 >> 4];
+ if (aldw != nullptr && !BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s(r%d),", aldw, byte2 & 0x0f);
+ format_dirw(stream, byte1);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0x96);
+}
+
+offs_t st9_disassembler::dasm_a6(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const aldw = s_aldw[byte1 >> 4];
+ if (aldw != nullptr)
+ {
+ util::stream_format(stream, "%-8s", aldw);
+ format_dirw(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, ",(r%d)", byte1);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xa6);
+}
+
+offs_t st9_disassembler::dasm_b4(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ if (!BIT(byte1, 0))
+ util::stream_format(stream, "(rr%d)+,", byte1 & 0x0e);
+ format_dir(stream, opcodes.r8(pc + 2));
+ if (BIT(byte1, 0))
+ util::stream_format(stream, ",(rr%d)+", byte1 & 0x0e);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xb4);
+}
+
+offs_t st9_disassembler::dasm_b6(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 0))
+ return dasm_unknown(stream, opc);
+ else
+ {
+ util::stream_format(stream, "%-8s", BIT(opc, 0) ? "popuw" : "pushuw");
+ format_dirw(stream, byte1);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9p_disassembler::dasm_b6(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", BIT(opc, 0) ? "unlinku" : "linku");
+ format_dirw(stream, byte1 & 0xfe);
+ if (BIT(opc, 0))
+ return 2 | SUPPORTED;
+ else
+ {
+ stream << ',';
+ format_imm(stream, opcodes.r8(pc + 2));
+ return 3 | SUPPORTED;
+ }
+ }
+ else
+ return st9_disassembler::dasm_b6(stream, opc, byte1, pc, opcodes);
+}
+
+offs_t st9_disassembler::dasm_be(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const aldw = s_aldw[byte1 >> 4];
+ if (aldw != nullptr)
+ {
+ util::stream_format(stream, "%-8s(rr%d),", aldw, byte1 & 0x0e);
+ if (BIT(byte1, 0))
+ {
+ format_dirw(stream, opcodes.r8(pc + 2));
+ return 3 | SUPPORTED;
+ }
+ else
+ {
+ format_immw(stream, opcodes.r16(pc + 2));
+ return 4 | SUPPORTED;
+ }
+ }
+ else
+ return dasm_unknown(stream, 0xbe);
+}
+
+offs_t st9_disassembler::dasm_bf(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (!BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", "ldw");
+ format_dirw(stream, byte1);
+ stream << ',';
+ format_immw(stream, opcodes.r16(pc + 2));
+ return 4 | SUPPORTED;
+ }
+ else if (byte1 == 0x01)
+ {
+ stream << "halt";
+ return 2 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xbf);
+}
+
+offs_t st9_disassembler::dasm_c2(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = BIT(opc, 0) ? s_aldw[byte1 >> 4] : s_ald[byte1 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ if (!BIT(byte1, 0))
+ util::stream_format(stream, "-(rr%d),", byte1 & 0x0e);
+ if (BIT(opc, 0))
+ format_dirw(stream, opcodes.r8(pc + 2));
+ else
+ format_dir(stream, opcodes.r8(pc + 2));
+ if (BIT(byte1, 0))
+ util::stream_format(stream, ",-(rr%d)", byte1 & 0x0e);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, opc);
+}
+
+offs_t st9_disassembler::dasm_c4(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ if (!BIT(opc, 0))
+ util::stream_format(stream, "r%d,", byte1 & 0x0f);
+ format_label(stream, opcodes.r16(pc + 2));
+ if (BIT(opc, 0))
+ util::stream_format(stream, ",r%d", byte1 & 0x0f);
+ return 4 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, opc);
+}
+
+offs_t st9_disassembler::dasm_c6(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", "ext");
+ format_dirw(stream, byte1 & 0xfe);
+ return 2 | SUPPORTED;
+ }
+ else
+ {
+ util::stream_format(stream, "%-8s", "dwjnz");
+ format_dirw(stream, byte1);
+ stream << ',';
+ format_label(stream, pc + 3 + s8(opcodes.r8(pc + 2)));
+ return 3 | STEP_COND | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_c7(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ switch (byte1 & 0x07)
+ {
+ case 0:
+ util::stream_format(stream, "%-8s", "srp");
+ format_imm(stream, byte1 >> 3);
+ return 2 | SUPPORTED;
+
+ case 4:
+ util::stream_format(stream, "%-8s", "srp0");
+ format_imm(stream, byte1 >> 3);
+ return 2 | SUPPORTED;
+
+ case 5:
+ util::stream_format(stream, "%-8s", "srp1");
+ format_imm(stream, byte1 >> 3);
+ return 2 | SUPPORTED;
+
+ case 2: case 6:
+ util::stream_format(stream, "%-8s", "spp");
+ format_imm(stream, byte1 >> 2);
+ return 2 | SUPPORTED;
+
+ default:
+ return dasm_unknown(stream, 0xc7);
+ }
+}
+
+offs_t st9_disassembler::dasm_cf(std::ostream &stream, u8 opc, u8 byte1) const
+{
+ if (BIT(byte1, 0))
+ return dasm_unknown(stream, opc);
+ else
+ {
+ util::stream_format(stream, "%-8s", BIT(opc, 4) ? "incw" : "decw");
+ format_dirw(stream, byte1);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_d4(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 0))
+ return dasm_unknown(stream, 0xd4);
+ else
+ {
+ util::stream_format(stream, "%-8s(", "jp");
+ format_dirw(stream, byte1);
+ stream << ')';
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9p_disassembler::dasm_d4(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 0))
+ {
+ util::stream_format(stream, "%-8s", "link");
+ format_dirw(stream, byte1 & 0xfe);
+ stream << ',';
+ format_imm(stream, opcodes.r8(pc + 2));
+ return 3 | SUPPORTED;
+ }
+ else
+ return st9_disassembler::dasm_d4(stream, byte1, pc, opcodes);
+}
+
+offs_t st9_disassembler::dasm_d5(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const aldw = s_aldw[byte1 >> 4];
+ if (aldw != nullptr)
+ {
+ util::stream_format(stream, "%-8s", aldw);
+ if (!BIT(byte1, 0))
+ util::stream_format(stream, "(rr%d)+,", byte1 & 0x0e);
+ format_dirw(stream, opcodes.r8(pc + 2));
+ if (BIT(byte1, 0))
+ util::stream_format(stream, ",(rr%d)+", byte1 & 0x0e);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xd5);
+}
+
+offs_t st9_disassembler::dasm_e2(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const aldw = s_aldw[byte1 >> 4];
+ if (aldw != nullptr)
+ {
+ util::stream_format(stream, "%-8s", aldw);
+ if (!BIT(byte1, 0))
+ util::stream_format(stream, "rr%d,", byte1 & 0x0e);
+ format_label(stream, opcodes.r16(pc + 2));
+ if (BIT(byte1, 0))
+ util::stream_format(stream, ",rr%d", byte1 & 0x0e);
+ return 4 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xe2);
+}
+
+offs_t st9_disassembler::dasm_e6(std::ostream &stream, u8 byte1, u8 byte2) const
+{
+ const char *const ald = s_ald[byte2 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s(r%d),", ald, byte2 & 0x0f);
+ format_dir(stream, byte1);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xe6);
+}
+
+offs_t st9_disassembler::dasm_e7(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ if (ald != nullptr)
+ {
+ util::stream_format(stream, "%-8s", ald);
+ format_dir(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, ",(r%d)", byte1 & 0x0f);
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xe7);
+}
+
+offs_t st9_disassembler::dasm_ef(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 0))
+ {
+ if (byte1 == 0x01)
+ {
+ stream << "wfi";
+ return 2 | SUPPORTED;
+ }
+ else if (byte1 == 0x05)
+ {
+ stream << "eret";
+ return 2 | STEP_OUT | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xef);
+ }
+ else
+ {
+ util::stream_format(stream, "%-8s", "ldw");
+ format_dirw(stream, opcodes.r8(pc + 2));
+ stream << ',';
+ format_dirw(stream, byte1);
+ return 3 | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_f2(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ if (BIT(byte1, 4))
+ {
+ const u8 byte2 = opcodes.r8(pc + 2);
+ util::stream_format(stream, "%-8sr%d.%d,r%d.%s%d", "bld", byte1 & 0x0f, byte1 >> 5, byte2 & 0x0f, BIT(byte2, 4) ? "!" : "", byte2 >> 5);
+ return 3 | SUPPORTED;
+ }
+ else
+ {
+ util::stream_format(stream, "%-8sr%d.%d", "btset", byte1 & 0x0f, byte1 >> 5);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9_disassembler::dasm_f3(std::ostream &stream, u8 byte1, offs_t pc, const st9_disassembler::data_buffer &opcodes) const
+{
+ const char *const ald = s_ald[byte1 >> 4];
+ // Byte 1 for LD (rr),#N is documented as [XTN=F|dst,0], but actual code uses dst,1 instead
+ if (ald != nullptr /*&& !BIT(byte1, 0)*/)
+ {
+ util::stream_format(stream, "%-8s(rr%d),", ald, byte1 & 0x0e);
+ format_imm(stream, opcodes.r8(pc + 2));
+ return 3 | SUPPORTED;
+ }
+ else
+ return dasm_unknown(stream, 0xf3);
+}
+
+offs_t st9_disassembler::dasm_f6(std::ostream &stream, u8 byte1) const
+{
+ if (BIT(byte1, 0))
+ return dasm_unknown(stream, 0xf6);
+ else
+ {
+ util::stream_format(stream, "%-8s(rr%d).%d", "btset", byte1 & 0x0e, byte1 >> 5);
+ return 2 | SUPPORTED;
+ }
+}
+
+offs_t st9p_disassembler::dasm_f6(std::ostream &stream, u8 byte1) const
+{
+ if (byte1 == 0x01)
+ {
+ stream << "rets";
+ return 2 | STEP_OUT | SUPPORTED;
+ }
+ else
+ return st9_disassembler::dasm_f6(stream, byte1);
+}
+
+offs_t st9_disassembler::disassemble(std::ostream &stream, offs_t pc, const st9_disassembler::data_buffer &opcodes, const st9_disassembler::data_buffer &params)
+{
+ const u8 opc = opcodes.r8(pc);
+
+ switch (opc)
+ {
+ case 0x00:
+ stream << "ei";
+ return 1 | SUPPORTED;
+
+ case 0x01:
+ stream << "scf";
+ return 1 | SUPPORTED;
+
+ case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: case 0x62: case 0x82: case 0x92: case 0xa2:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ const char *const ald = s_ald[opc >> 4];
+ assert(ald != nullptr);
+ util::stream_format(stream, "%-8sr%d,r%d", ald, byte1 >> 4, byte1 & 0x0f);
+ return 2 | SUPPORTED;
+ }
+
+ case 0x03: case 0x13: case 0x23: case 0x33: case 0x43: case 0x53: case 0x63: case 0x83: case 0x93: case 0xa3:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ const char *const ald = s_ald[opc >> 4];
+ assert(ald != nullptr);
+ util::stream_format(stream, "%-8sr%d,(r%d)", ald, byte1 >> 4, byte1 & 0x0f);
+ return 2 | SUPPORTED;
+ }
+
+ case 0x04: case 0x14: case 0x24: case 0x34: case 0x44: case 0x54: case 0x64: case 0x84: case 0x94: case 0xa4: case 0xf4:
+ {
+ const char *const ald = s_ald[opc >> 4];
+ assert(ald != nullptr);
+ util::stream_format(stream, "%-8s", ald);
+ format_dir(stream, opcodes.r8(pc + 2));
+ stream << ',';
+ format_dir(stream, opcodes.r8(pc + 1));
+ return 3 | SUPPORTED;
+ }
+
+ case 0x05: case 0x15: case 0x25: case 0x35: case 0x45: case 0x55: case 0x65: case 0x85: case 0x95: case 0xa5: case 0xf5:
+ {
+ const char *const ald = s_ald[opc >> 4];
+ assert(ald != nullptr);
+ util::stream_format(stream, "%-8s", ald);
+ format_dir(stream, opcodes.r8(pc + 1));
+ stream << ',';
+ format_imm(stream, opcodes.r8(pc + 2));
+ return 3 | SUPPORTED;
+ }
+
+ case 0x06:
+ return dasm_06(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x07: case 0x17: case 0x27: case 0x37: case 0x47: case 0x57: case 0x67: case 0x87: case 0x97: case 0xa7:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ const char *const aldw = s_aldw[opc >> 4];
+ assert(aldw != nullptr);
+ util::stream_format(stream, "%-8s", aldw);
+ if (BIT(byte1, 0))
+ {
+ format_dirw(stream, byte1 & 0xfe);
+ stream << ',';
+ format_immw(stream, opcodes.r16(pc + 2));
+ return 4 | SUPPORTED;
+ }
+ else
+ {
+ format_dirw(stream, opcodes.r8(pc + 2));
+ stream << ',';
+ format_dirw(stream, byte1);
+ return 3 | SUPPORTED;
+ }
+ }
+
+ case 0x08: case 0x18: case 0x28: case 0x38: case 0x48: case 0x58: case 0x68: case 0x78:
+ case 0x88: case 0x98: case 0xa8: case 0xb8: case 0xc8: case 0xd8: case 0xe8: case 0xf8:
+ util::stream_format(stream, "%-8sr%d,", "ld", opc >> 4);
+ format_dir(stream, opcodes.r8(pc + 1));
+ return 2 | SUPPORTED;
+
+ case 0x09: case 0x19: case 0x29: case 0x39: case 0x49: case 0x59: case 0x69: case 0x79:
+ case 0x89: case 0x99: case 0xa9: case 0xb9: case 0xc9: case 0xd9: case 0xe9: case 0xf9:
+ util::stream_format(stream, "%-8s", "ld");
+ format_dir(stream, opcodes.r8(pc + 1));
+ util::stream_format(stream, ",r%d", opc >> 4);
+ return 2 | SUPPORTED;
+
+ case 0x0a: case 0x1a: case 0x2a: case 0x3a: case 0x4a: case 0x5a: case 0x6a: case 0x7a:
+ case 0x8a: case 0x9a: case 0xaa: case 0xba: case 0xca: case 0xda: case 0xea: case 0xfa:
+ util::stream_format(stream, "%-8sr%d,", "djnz", opc >> 4);
+ format_label(stream, pc + 2 + s8(opcodes.r8(pc + 1)));
+ return 2 | STEP_COND | SUPPORTED;
+
+ case 0x0b: case 0x1b: case 0x2b: case 0x3b: case 0x4b: case 0x5b: case 0x6b: case 0x7b:
+ case 0x8b: case 0x9b: case 0xab: case 0xbb: case 0xcb: case 0xdb: case 0xeb: case 0xfb:
+ util::stream_format(stream, "jr%-6s", s_cc[opc >> 4]);
+ format_label(stream, pc + 2 + s8(opcodes.r8(pc + 1)));
+ return 2 | ((opc & 0x70) != 0 ? STEP_COND : 0) | SUPPORTED;
+
+ case 0x0c: case 0x1c: case 0x2c: case 0x3c: case 0x4c: case 0x5c: case 0x6c: case 0x7c:
+ case 0x8c: case 0x9c: case 0xac: case 0xbc: case 0xcc: case 0xdc: case 0xec: case 0xfc:
+ util::stream_format(stream, "%-8sr%d,", "ld", opc >> 4);
+ format_imm(stream, opcodes.r8(pc + 1));
+ return 2 | SUPPORTED;
+
+ case 0x0d: case 0x1d: case 0x2d: case 0x3d: case 0x4d: case 0x5d: case 0x6d: case 0x7d:
+ case 0x8d: case 0x9d: case 0xad: case 0xbd: case 0xcd: case 0xdd: case 0xed: case 0xfd:
+ util::stream_format(stream, "jp%-6s", s_cc[opc >> 4]);
+ format_label(stream, opcodes.r16(pc + 1));
+ return 3 | ((opc & 0x70) != 0 ? STEP_COND : 0) | SUPPORTED;
+
+ case 0x0e: case 0x1e: case 0x2e: case 0x3e: case 0x4e: case 0x5e: case 0x6e: case 0x8e: case 0x9e: case 0xae:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ const char *const aldw = s_aldw[opc >> 4];
+ assert(aldw != nullptr);
+ util::stream_format(stream, "%-8s", aldw);
+ if (BIT(byte1, 4))
+ stream << '(';
+ util::stream_format(stream, "rr%d", (byte1 & 0xe0) >> 4);
+ if (BIT(byte1, 4))
+ stream << ')';
+ stream << ',';
+ if (BIT(byte1, 0))
+ stream << '(';
+ util::stream_format(stream, "rr%d", byte1 & 0x0e);
+ if (BIT(byte1, 0))
+ stream << ')';
+ return 2 | SUPPORTED;
+ }
+
+ case 0x0f:
+ return dasm_0f(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x10:
+ stream << "di";
+ return 1 | SUPPORTED;
+
+ case 0x11:
+ stream << "rcf";
+ return 1 | SUPPORTED;
+
+ case 0x16:
+ util::stream_format(stream, "%-8s", "xch");
+ format_dir(stream, opcodes.r8(pc + 2));
+ stream << ',';
+ format_dir(stream, opcodes.r8(pc + 1));
+ return 3 | SUPPORTED;
+
+ case 0x1f:
+ return dasm_1f(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x20: case 0x30: case 0x40: case 0x50: case 0x70: case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xc0: case 0xd0: case 0xe0: case 0xf0:
+ {
+ const char *const inst = s_unary_inst[opc >> 4];
+ assert(inst != nullptr);
+ util::stream_format(stream, "%-8s", inst);
+ format_dir(stream, opcodes.r8(pc + 1));
+ return 2 | SUPPORTED;
+ }
+
+ case 0x21: case 0x31: case 0x41: case 0x51: case 0x71: case 0x81: case 0x91: case 0xa1: case 0xb1: case 0xc1: case 0xd1: case 0xe1: case 0xf1:
+ {
+ const char *const inst = s_unary_inst[opc >> 4];
+ assert(inst != nullptr);
+ util::stream_format(stream, "%-8s(", inst);
+ format_dir(stream, opcodes.r8(pc + 1));
+ stream << ')';
+ return 2 | SUPPORTED;
+ }
+
+ case 0x26:
+ return dasm_26(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x2f:
+ return dasm_2f(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x36:
+ return dasm_36(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x3f:
+ return dasm_3f(stream, pc, opcodes);
+
+ case 0x46:
+ stream << "ret";
+ return 1 | STEP_OUT | SUPPORTED;
+
+ case 0x4f: case 0x5f:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8srr%d,r%d", BIT(opc, 4) ? "div" : "mul", byte1 >> 4, byte1 & 0x0f);
+ return 2 | SUPPORTED;
+ }
+
+ case 0x56:
+ {
+ const u8 byte2 = opcodes.r8(pc + 2);
+ util::stream_format(stream, "%-8srr%d,rr%d,", "divws", byte2 >> 4, byte2 & 0x0f);
+ format_dirw(stream, opcodes.r8(pc + 1));
+ return 3 | SUPPORTED;
+ }
+
+ case 0x60:
+ return dasm_60(stream, opcodes.r8(pc + 1), opcodes.r8(pc + 2));
+
+ case 0x61:
+ stream << "ccf";
+ return 1 | SUPPORTED;
+
+ case 0x66: case 0x76:
+ util::stream_format(stream, "%-8s", BIT(opc, 4) ? "pop" : "push");
+ format_dir(stream, opcodes.r8(pc + 1));
+ return 2 | SUPPORTED;
+
+ case 0x6f:
+ return dasm_6f(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x72:
+ return dasm_72(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x73:
+ return dasm_73(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x74:
+ return dasm_74(stream, opcodes.r8(pc + 1));
+
+ case 0x75:
+ return dasm_75(stream, opcodes.r8(pc + 1));
+
+ case 0x77: case 0xf7:
+ util::stream_format(stream, "%-8s(", BIT(opc, 7) ? "push" : "pop");
+ format_dir(stream, opcodes.r8(pc + 1));
+ stream << ')';
+ return 2 | SUPPORTED;
+
+ case 0x7e:
+ return dasm_7e(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x7f:
+ return dasm_7f(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x86:
+ return dasm_86(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x8f:
+ return dasm_8f(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0x96:
+ return dasm_96(stream, opcodes.r8(pc + 1), opcodes.r8(pc + 1));
+
+ case 0x9f:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8sr%d,(rr%d),", BIT(byte1, 4) ? "cpjt" : "cpjf", byte1 & 0x0f, (byte1 & 0xe0) >> 4);
+ format_label(stream, pc + 3 + s8(opcodes.r8(pc + 2)));
+ return 3 | STEP_COND | SUPPORTED;
+ }
+
+ case 0xa6:
+ return dasm_a6(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xaf:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8sr%d.%d,", BIT(byte1, 4) ? "btjf" : "btjt", byte1 & 0x0f, byte1 >> 5);
+ format_label(stream, pc + 3 + s8(opcodes.r8(pc + 2)));
+ return 3 | STEP_COND | SUPPORTED;
+ }
+
+ case 0xb2: case 0xb3:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8s", "ld");
+ if (BIT(opc, 0))
+ util::stream_format(stream, "r%d,", byte1 >> 4);
+ format_disp(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "(r%d)", byte1 & 0x0f);
+ if (!BIT(opc, 0))
+ util::stream_format(stream, ",r%d", byte1 >> 4);
+ return 3 | SUPPORTED;
+ }
+
+ case 0xb4:
+ return dasm_b4(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xb5:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ if (BIT(byte1, 0))
+ util::stream_format(stream, "%-8sr%d,(rr%d)", "ld", byte1 >> 4, byte1 & 0x0e);
+ else
+ util::stream_format(stream, "%-8s(rr%d),r%d", "ld", byte1 & 0x0e, byte1 >> 4);
+ return 2 | SUPPORTED;
+ }
+
+ case 0xb6: case 0xb7:
+ return dasm_b6(stream, opc, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xbe:
+ return dasm_be(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xbf:
+ return dasm_bf(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xc2: case 0xc3:
+ return dasm_c2(stream, opc, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xc4: case 0xc5:
+ return dasm_c4(stream, opc, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xc6:
+ return dasm_c6(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xc7:
+ return dasm_c7(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xce:
+ stream << "etrap";
+ return 1 | STEP_OVER | SUPPORTED;
+
+ case 0xcf: case 0xdf:
+ return dasm_cf(stream, opc, opcodes.r8(pc + 1));
+
+ case 0xd2:
+ util::stream_format(stream, "%-8s", "call");
+ format_label(stream, opcodes.r16(pc + 1));
+ return 3 | STEP_OVER | SUPPORTED;
+
+ case 0xd3:
+ stream << "iret";
+ return 1 | STEP_OUT | SUPPORTED;
+
+ case 0xd4:
+ return dasm_d4(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xd5:
+ return dasm_d5(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xd6:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "ld%c%-5c(rr%d)+,(rr%d)+", "pd"[BIT(byte1, 4)], "pd"[BIT(byte1, 0)], (byte1 & 0xe0) >> 4, byte1 & 0x0e);
+ return 2 | SUPPORTED;
+ }
+
+ case 0xd7:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8s", "ld");
+ if (BIT(byte1, 0))
+ util::stream_format(stream, "(r%d)+,(rr%d)+", byte1 >> 4, byte1 & 0x0e);
+ else
+ util::stream_format(stream, "(rr%d)+,(r%d)+", byte1 & 0x0e, byte1 >> 4);
+ return 2 | SUPPORTED;
+ }
+
+ case 0xde:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8s", "ldw");
+ if (!BIT(byte1, 4))
+ util::stream_format(stream, "rr%d,", byte1 >> 4);
+ format_disp(stream, opcodes.r8(pc + 2));
+ util::stream_format(stream, "(r%d)", byte1 & 0x0f);
+ if (BIT(byte1, 4))
+ util::stream_format(stream, ",rr%d", (byte1 & 0xe0) >> 4);
+ return 3 | SUPPORTED;
+ }
+
+ case 0xe2:
+ return dasm_e2(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xe3:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8s", "ldw");
+ if (BIT(byte1, 4))
+ stream << '(';
+ util::stream_format(stream, "rr%d", (byte1 & 0xe0) >> 4);
+ if (BIT(byte1, 4))
+ stream << ')';
+ stream << ',';
+ if (BIT(byte1, 0))
+ stream << '(';
+ util::stream_format(stream, "rr%d", byte1 & 0x0e);
+ if (BIT(byte1, 0))
+ stream << ')';
+ return 2 | SUPPORTED;
+ }
+
+ case 0xe4:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8sr%d,(r%d)", "ld", byte1 >> 4, byte1 & 0x0f);
+ return 2 | SUPPORTED;
+ }
+
+ case 0xe5:
+ {
+ const u8 byte1 = opcodes.r8(pc + 1);
+ util::stream_format(stream, "%-8s(r%d),r%d", "ld", byte1 >> 4, byte1 & 0x0f);
+ return 2 | SUPPORTED;
+ }
+
+ case 0xe6:
+ return dasm_e6(stream, opcodes.r8(pc + 1), opcodes.r8(pc + 2));
+
+ case 0xe7:
+ return dasm_e7(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xee:
+ stream << "spm";
+ return 1 | SUPPORTED;
+
+ case 0xef:
+ return dasm_ef(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xf2:
+ return dasm_f2(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xf3:
+ return dasm_f3(stream, opcodes.r8(pc + 1), pc, opcodes);
+
+ case 0xf6:
+ return dasm_f6(stream, opcodes.r8(pc + 1));
+
+ case 0xfe:
+ stream << "sdm";
+ return 1 | SUPPORTED;
+
+ case 0xff:
+ stream << "nop";
+ return 1 | SUPPORTED;
+
+ default:
+ return dasm_unknown(stream, opc);
+ }
+}
diff --git a/src/devices/cpu/st9/st9dasm.h b/src/devices/cpu/st9/st9dasm.h
new file mode 100644
index 00000000000..95a7169ee98
--- /dev/null
+++ b/src/devices/cpu/st9/st9dasm.h
@@ -0,0 +1,90 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+
+#ifndef MAME_CPU_ST9_ST9DASM_H
+#define MAME_CPU_ST9_ST9DASM_H
+
+#pragma once
+
+class st9_disassembler : public util::disasm_interface
+{
+public:
+ // construction/destruction
+ st9_disassembler();
+
+protected:
+ // util::disasm_interface overrides
+ virtual u32 opcode_alignment() const override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+
+ // formatting helpers
+ void format_dir(std::ostream &stream, u8 r) const;
+ void format_dirw(std::ostream &stream, u8 rr) const;
+ void format_imm(std::ostream &stream, u8 n) const;
+ void format_immw(std::ostream &stream, u16 n) const;
+ void format_disp(std::ostream &stream, s8 n) const;
+ void format_dispw(std::ostream &stream, u16 nn) const;
+ void format_label(std::ostream &stream, u16 nn) const;
+
+ // disassembly helpers
+ offs_t dasm_unknown(std::ostream &stream, u8 opc) const;
+ offs_t dasm_06(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_0f(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_1f(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_26(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_2f(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_36(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ virtual offs_t dasm_3f(std::ostream &stream, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_60(std::ostream &stream, u8 byte1, u8 byte2) const;
+ offs_t dasm_6f(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_72(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ virtual offs_t dasm_73(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_74(std::ostream &stream, u8 byte1) const;
+ virtual offs_t dasm_75(std::ostream &stream, u8 byte1) const;
+ offs_t dasm_7e(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_7f(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_86(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_8f(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_96(std::ostream &stream, u8 byte1, u8 byte2) const;
+ offs_t dasm_a6(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_b4(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ virtual offs_t dasm_b6(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_be(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_bf(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_c2(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_c4(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_c6(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_c7(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_cf(std::ostream &stream, u8 opc, u8 byte1) const;
+ virtual offs_t dasm_d4(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_d5(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_e2(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_e6(std::ostream &stream, u8 byte1, u8 byte2) const;
+ offs_t dasm_e7(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_ef(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_f2(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ offs_t dasm_f3(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const;
+ virtual offs_t dasm_f6(std::ostream &stream, u8 byte1) const;
+};
+
+class st9p_disassembler : public st9_disassembler
+{
+public:
+ // construction/destruction
+ using st9_disassembler::st9_disassembler;
+
+protected:
+ // util::disasm_interface overrides
+ virtual u32 interface_flags() const override;
+ virtual u32 page_address_bits() const override;
+
+ // st9_disassembler overrides
+ virtual offs_t dasm_3f(std::ostream &stream, offs_t pc, const data_buffer &opcodes) const override;
+ virtual offs_t dasm_73(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const override;
+ virtual offs_t dasm_75(std::ostream &stream, u8 byte1) const override;
+ virtual offs_t dasm_b6(std::ostream &stream, u8 opc, u8 byte1, offs_t pc, const data_buffer &opcodes) const override;
+ virtual offs_t dasm_d4(std::ostream &stream, u8 byte1, offs_t pc, const data_buffer &opcodes) const override;
+ virtual offs_t dasm_f6(std::ostream &stream, u8 byte1) const override;
+};
+
+#endif // MAME_CPU_ST9_ST9DASM_H
diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp
index 54b676df155..78bb666ebf2 100644
--- a/src/tools/unidasm.cpp
+++ b/src/tools/unidasm.cpp
@@ -164,6 +164,7 @@ using util::BIT;
#include "cpu/ssem/ssemdasm.h"
#include "cpu/ssp1601/ssp1601d.h"
#include "cpu/st62xx/st62xx_dasm.h"
+#include "cpu/st9/st9dasm.h"
#include "cpu/superfx/sfx_dasm.h"
#include "cpu/t11/t11dasm.h"
#include "cpu/tlcs870/tlcs870d.h"
@@ -605,6 +606,8 @@ static const dasm_table_entry dasm_table[] =
{ "ssem", le, 0, []() -> util::disasm_interface * { return new ssem_disassembler; } },
{ "ssp1601", be, -1, []() -> util::disasm_interface * { return new ssp1601_disassembler; } },
{ "st62xx", le, 0, []() -> util::disasm_interface * { return new st62xx_disassembler; } },
+ { "st9", be, 0, []() -> util::disasm_interface * { return new st9_disassembler; } },
+ { "st9p", be, 0, []() -> util::disasm_interface * { return new st9p_disassembler; } },
{ "superfx", le, 0, []() -> util::disasm_interface * { return new superfx_disassembler(&superfx_unidasm); } },
{ "t11", le, 0, []() -> util::disasm_interface * { return new t11_disassembler; } },
{ "tlcs870", le, 0, []() -> util::disasm_interface * { return new tlcs870_disassembler; } },