From e2edca4404217c4d346ce17b2d029e000e2bbeef Mon Sep 17 00:00:00 2001 From: AJR Date: Sun, 18 Jun 2023 16:48:00 -0400 Subject: unidasm: Add disassemblers for ST9 and ST9+ architectures --- scripts/src/cpu.lua | 10 + src/devices/cpu/st9/st9dasm.cpp | 1373 +++++++++++++++++++++++++++++++++++++++ src/devices/cpu/st9/st9dasm.h | 90 +++ src/tools/unidasm.cpp | 3 + 4 files changed, 1476 insertions(+) create mode 100644 src/devices/cpu/st9/st9dasm.cpp create mode 100644 src/devices/cpu/st9/st9dasm.h diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 8c8b0f9bb51..a7b9bc3745c 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -3833,3 +3833,13 @@ if opt_tool(CPUS, "INTERDATA16") then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/interdata16/dasm16.cpp") table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/interdata16/dasm16.h") end + +-------------------------------------------------- +-- SGS-Thomson ST9, disassembler only +--@src/devices/cpu/st9/st9.h,CPUS["ST9"] = true +-------------------------------------------------- + +if opt_tool(CPUS, "ST9") then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/st9/st9dasm.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/st9/st9dasm.h") +end 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 ¶ms) +{ + 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 ¶ms) 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; } }, -- cgit v1.2.3