diff options
author | 2020-06-04 16:15:37 -0400 | |
---|---|---|
committer | 2020-06-04 16:21:46 -0400 | |
commit | f84e4d036b2e8a9a7d3b8f06b56e4aea49174f6e (patch) | |
tree | fa3490332e5eb0e495282ec5a3e2993edd1e6fad /src/devices/cpu/mn1880 | |
parent | f49a2f5b8ff8429c1a50fde3cee86af5d24329c9 (diff) |
New machines marked as NOT_WORKING
----------------------------------
Novation BassStation Rack Analogue Synthesizer Module [DBWBP]
Novation Drum Station [DBWBP]
Novation Super Bass Station [DBWBP]
Add disassembler and skeleton CPU device for Panasonic MN1880 architecture [AJR]
Diffstat (limited to 'src/devices/cpu/mn1880')
-rw-r--r-- | src/devices/cpu/mn1880/mn1880.cpp | 114 | ||||
-rw-r--r-- | src/devices/cpu/mn1880/mn1880.h | 57 | ||||
-rw-r--r-- | src/devices/cpu/mn1880/mn1880d.cpp | 568 | ||||
-rw-r--r-- | src/devices/cpu/mn1880/mn1880d.h | 55 |
4 files changed, 794 insertions, 0 deletions
diff --git a/src/devices/cpu/mn1880/mn1880.cpp b/src/devices/cpu/mn1880/mn1880.cpp new file mode 100644 index 00000000000..cf837a53d28 --- /dev/null +++ b/src/devices/cpu/mn1880/mn1880.cpp @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Panasonic MN1880 family + + Currently this device is just a stub with no actual execution core. + +***************************************************************************/ + +#include "emu.h" +#include "mn1880.h" +#include "mn1880d.h" + +// device type definitions +DEFINE_DEVICE_TYPE(MN1880, mn1880_device, "mn1880", "Panasonic MN1880") + +mn1880_device::mn1880_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : cpu_device(mconfig, MN1880, tag, owner, clock) + , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 16, 0) + , m_ip(0) + , m_fs(0) + , m_xp(0) + , m_yp(0) + , m_sp(0) + , m_lp(0) + , m_icount(0) +{ +} + +std::unique_ptr<util::disasm_interface> mn1880_device::create_disassembler() +{ + return std::make_unique<mn1880_disassembler>(); +} + +device_memory_interface::space_config_vector mn1880_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_DATA, &m_data_config) + }; +} + +void mn1880_device::device_start() +{ + space(AS_PROGRAM).cache(m_cache); + space(AS_DATA).specific(m_data); + set_icountptr(m_icount); + + state_add(MN1880_IP, "IP", m_ip); + state_add(STATE_GENPC, "GENPC", m_ip).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_ip).noshow(); + state_add(MN1880_FS, "FS", m_fs); + state_add(STATE_GENFLAGS, "FLAGS", m_fs).formatstr("%10s").noshow(); + state_add(MN1880_XP, "XP", m_xp); + state_add(MN1880_YP, "YP", m_yp); + state_add<u8>(MN1880_XPL, "XPl", + [this] () { return m_xp & 0x00ff; }, + [this] (u8 data) { m_xp = (m_xp & 0xff00) | data; } + ).noshow(); + state_add<u8>(MN1880_XPH, "XPh", + [this] () { return (m_xp & 0xff00) >> 8; }, + [this] (u8 data) { m_xp = (m_xp & 0x00ff) | u16(data) << 8; } + ).noshow(); + state_add<u8>(MN1880_YPL, "YPl", + [this] () { return m_yp & 0x00ff; }, + [this] (u8 data) { m_yp = (m_yp & 0xff00) | data; } + ).noshow(); + state_add<u8>(MN1880_YPH, "YPh", + [this] () { return (m_yp & 0xff00) >> 8; }, + [this] (u8 data) { m_yp = (m_yp & 0x00ff) | u16(data) << 8; } + ).noshow(); + state_add(MN1880_SP, "SP", m_sp); + state_add(MN1880_LP, "LP", m_lp); + + save_item(NAME(m_ip)); + save_item(NAME(m_fs)); + save_item(NAME(m_xp)); + save_item(NAME(m_yp)); + save_item(NAME(m_sp)); + save_item(NAME(m_lp)); +} + +void mn1880_device::device_reset() +{ + m_fs &= 0xc0; // CF & ZF might or might not be cleared as well + m_sp = 0x0100; + // TBD: is LP also initialized at reset? +} + +void mn1880_device::execute_run() +{ + m_ip = m_cache.read_word(0); + + debugger_instruction_hook(m_ip); + + m_icount = 0; +} + +void mn1880_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + str = string_format("%c%c%c%c:RC=%-2d", + BIT(m_fs, 7) ? 'C' : '.', // Carry flag + BIT(m_fs, 6) ? 'Z' : '.', // Zero flag + BIT(m_fs, 5) ? 'D' : '.', // Direct flag + BIT(m_fs, 4) ? 'A' : '.', // Auto-repeat flag + m_fs & 0x0f); + break; + } +} diff --git a/src/devices/cpu/mn1880/mn1880.h b/src/devices/cpu/mn1880/mn1880.h new file mode 100644 index 00000000000..e4ab2427f46 --- /dev/null +++ b/src/devices/cpu/mn1880/mn1880.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_MN1880_MN1880_H +#define MAME_CPU_MN1880_MN1880_H + +#pragma once + +class mn1880_device : public cpu_device +{ +public: + mn1880_device(const machine_config &config, const char *tag, device_t *owner, u32 clock); + + enum { + MN1880_IP, MN1880_FS, + MN1880_XP, MN1880_YP, + MN1880_XPL, MN1880_XPH, MN1880_YPL, MN1880_YPH, + MN1880_SP, MN1880_LP + }; + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual void execute_run() override; + + // device_disasm_interface overrides + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + +private: + // address spaces + address_space_config m_program_config; + address_space_config m_data_config; + memory_access<16, 0, 0, ENDIANNESS_BIG>::cache m_cache; + memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_data; + + // internal state + u16 m_ip; + u8 m_fs; + u16 m_xp; + u16 m_yp; + u16 m_sp; + u16 m_lp; + s32 m_icount; +}; + +DECLARE_DEVICE_TYPE(MN1880, mn1880_device) + +#endif // MAME_CPU_MN1880_MN1880_H diff --git a/src/devices/cpu/mn1880/mn1880d.cpp b/src/devices/cpu/mn1880/mn1880d.cpp new file mode 100644 index 00000000000..01ab3fac038 --- /dev/null +++ b/src/devices/cpu/mn1880/mn1880d.cpp @@ -0,0 +1,568 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Panasonic MN1880 family disassembler + + Due to the dearth of available documentation for the MN1880 series, + its instruction list has been reconstructed from MN1870 and MN1890 + manuals, a (decidedly incomplete) list of MN1880 instructions not + provided in the MN1870 series, and a few educated guesses based on + reverse engineering (which include CALL XP actually being provided by + the MN1880 despite the MN1870 manual claiming it as exclusive). + + The direct flag (bit 5 of the flag status register) is the key to + data memory addressing. When DF is cleared, the upper bytes of direct + addresses are zeroed; when DF is set, the upper address bytes are + taken from YPh for source operands and XPh for destination operands. + + Note that the REP opcode causes a temporary mode switch, decoding + up to 15 extra sets of operands for the following instruction. + REPEAT_COMBINED attempts to process this correctly by treating the + full sequence as a single instruction, but this option has been + disabled by default because it results in some repeated instructions + being dozens of bytes long and the formatted output being difficult + to read anyway since MAME requires it all be on a single line. + +***************************************************************************/ + +#include "emu.h" +#include "mn1880d.h" + +#define REPEAT_COMBINED 0 + +mn1880_disassembler::mn1880_disassembler(const char *const *inst_names) + : util::disasm_interface() + , m_inst_names(inst_names) +{ +} + +mn1880_disassembler::mn1880_disassembler() + : mn1880_disassembler(s_inst_names) +{ +} + +// MOV, RDTBL, MOV1 and MOV1N may also be known as MV, MVROM, MV1 and MV1CPL +const char *const mn1880_disassembler::s_inst_names[256] = +{ + "nop", "rep", "rep", "rep", "rep", "rep", "rep", "rep", + "rep", "rep", "rep", "rep", "rep", "rep", "rep", "rep", + "clr", "clr", "clr", "clr", "clr", "clr", "clr", "clr", + "set", "set", "set", "set", "set", "set", "set", "set", + "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", + "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", + nullptr, "movl", nullptr, "movl", "movl", "movl", "mov", "mov", + "movl", "movl", "movl", "movl", "asl", "asl", "asr", "asr", + "dec", "dec", "not", "not", "cmpm", "cmpm", "xch4", "xch4", + "inc", "inc", "clr", "clr", "rol", "rol", "ror", "ror", + "cmpm", "div", "cmpm", "movda", "mov", "mov", "mov", "mov", + "xch", "mul", "xch", nullptr, "movl", "movl", "movl", "movl", + "cmp", "cmp", "cmp", "cmp", "and", "and", "and", "and", + "xor", "xor", "xor", "xor", "or", "or", "or", "or", + "subc", "subc", "subc", "subc", "subd", "subd", "subd", "subd", + "addc", "addc", "addc", "addc", "addd", "addd", "addd", "addd", + "skip", "bc", "bz", "ble", "cmpl", "clr", "cmpl", "clr", + "br", "bnc", "bnz", "bgt", nullptr, "set", nullptr, "set", + "call", "call", "call", "call", "call", "call", "call", "call", + "call", "call", "call", "call", "call", "call", "call", "call", + "br", "br", "br", "br", "br", "br", "br", "br", + "br", "br", "br", "br", "br", "br", "br", "br", + nullptr, "pop", nullptr, "pop", "pop", "pop", "pop", "pop", + nullptr, "push", nullptr, "push", "push", "push", "push", "push", + "subcl", "div", "subcl", nullptr, "xch", "xch", "xch", "xch", + "addcl", "mul", "addcl", nullptr, "mov", "mov", "mov", "mov", + "cmp", "cmp", "cmp", "cmp", "xch", "xch", nullptr, "xch", + "mov", "mov", "mov", "mov", "mov", "mov", "mov", "mov", + "loop", "rloop", "loop", "rloop", "dec", "inc", "dec", "inc", + "addr", "addr", "addr", "addr", "addr", "addr", "addr", "addr", + "cmpbne", "cmpbne", "mov1", "wait", "ret", "reti", "br", "call", + "cmpbe", "cmpbe", "mov1n", "push", "br", "call", "rdtbl", "pi" +}; + +mn1870_disassembler::mn1870_disassembler() + : mn1880_disassembler(s_inst_names) +{ +} + +// STOP and HALT appear to be macros each implemented as a SET followed by a T1BNZ +// (their machine language codes are given as 19 16 21 16 FD and 18 16 20 16 FD) +const char *const mn1870_disassembler::s_inst_names[256] = +{ + "nop", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "clr", "clr", "clr", "clr", "clr", "clr", "clr", "clr", + "set", "set", "set", "set", "set", "set", "set", "set", + "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", "t1bnz", + "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", "t1bz", + nullptr, "movl", nullptr, "movl", nullptr, nullptr, "mov", "mov", + "movl", "movl", "movl", "movl", nullptr, nullptr, nullptr, nullptr, + "dec", "dec", "not", "not", "cmpm", "cmpm", "xch4", "xch4", + "inc", "inc", "clr", "clr", "rol", "rol", "ror", "ror", + "cmpm", "div", "cmpm", nullptr, "mov", "mov", "mov", "mov", + "xch", "mul", "xch", nullptr, "movl", "movl", "movl", "movl", + "cmp", "cmp", "cmp", "cmp", "and", "and", "and", "and", + "xor", "xor", "xor", "xor", "or", "or", "or", "or", + "subc", "subc", "subc", "subc", "subd", "subd", "subd", "subd", + "addc", "addc", "addc", "addc", "addd", "addd", "addd", "addd", + "skip", "bc", "bz", "ble", "cmpl", "clr", nullptr, "clr", + "br", "bnc", "bnz", "bgt", nullptr, "set", nullptr, "set", + "call", "call", "call", "call", "call", "call", "call", "call", + "call", "call", "call", "call", "call", "call", "call", "call", + "br", "br", "br", "br", "br", "br", "br", "br", + "br", "br", "br", "br", "br", "br", "br", "br", + "clr", "pop", "t1bnz", "pop", "pop", "pop", "pop", "pop", + "set", "push", "t1bz", "push", "push", "push", "push", "push", + nullptr, "div", nullptr, "decl", nullptr, nullptr, nullptr, nullptr, + nullptr, "mul", nullptr, "incl", "mov", "mov", "mov", "mov", + nullptr, "cmp", nullptr, "cmp", nullptr, "xch", nullptr, "xch", + "mov", "mov", "mov", "mov", nullptr, nullptr, nullptr, nullptr, + "loop", "rloop", "loop", "rloop", "dec", "inc", "dec", "inc", + nullptr, "addr", nullptr, "addr", nullptr, "addr", nullptr, "addr", + "cmpbne", "cmpbne", "mov1", nullptr, "ret", "reti", "br", "call", + "cmpbe", "cmpbe", "mov1n", "push", "br", "call", "rdtbl", nullptr +}; + +u32 mn1880_disassembler::opcode_alignment() const +{ + return 1; +} + +void mn1880_disassembler::format_direct(std::ostream &stream, u8 da) const +{ + util::stream_format(stream, "(x'%02X')", da); +} + +void mn1880_disassembler::format_direct16(std::ostream &stream, u16 da) const +{ + util::stream_format(stream, "(x'%04X')", da); +} + +void mn1880_disassembler::format_direct_bp(std::ostream &stream, u8 da, u8 bp) const +{ + util::stream_format(stream, "(x'%02X')%d", da, bp); +} + +void mn1880_disassembler::format_indirect_bp(std::ostream &stream, const char *ptr, u8 bp) const +{ + util::stream_format(stream, "(%s)%d", ptr, bp); +} + +void mn1880_disassembler::format_direct_masked(std::ostream &stream, u8 da, u8 mask) const +{ + util::stream_format(stream, "(x'%02X')x'%02X'", da, mask); +} + +void mn1880_disassembler::format_indirect_masked(std::ostream &stream, const char *ptr, u8 mask) const +{ + util::stream_format(stream, "(%s)x'%02X'", ptr, mask); +} + +void mn1880_disassembler::format_imm(std::ostream &stream, u8 imm) const +{ + util::stream_format(stream, "x'%02X'", imm); +} + +void mn1880_disassembler::format_imm4(std::ostream &stream, u8 imm) const +{ + util::stream_format(stream, "%d", imm & 0x0f); +} + +void mn1880_disassembler::format_imm16(std::ostream &stream, u16 imm) const +{ + util::stream_format(stream, "x'%04X'", imm); +} + +void mn1880_disassembler::format_rel(std::ostream &stream, u16 base, s8 disp) const +{ + util::stream_format(stream, "$x'%04X'", (base + disp) & 0xffff); +} + +void mn1880_disassembler::format_abs4k(std::ostream &stream, u16 label) const +{ + util::stream_format(stream, "x'%04X'", label); +} + +void mn1880_disassembler::format_abs64k(std::ostream &stream, u16 label) const +{ + util::stream_format(stream, "/x'%04X'", label); +} + +void mn1880_disassembler::dasm_operands(std::ostream &stream, u8 opcode, offs_t &pc, offs_t &flags, const mn1880_disassembler::data_buffer &opcodes) +{ + if (opcode < 0x10) + { + // REP + format_imm4(stream, opcode); + } + else if (opcode < 0x30) + { + // CLR, SET, T1BNZ, T1BZ direct + format_direct_bp(stream, opcodes.r8(pc++), opcode & 0x07); + if (opcode >= 0x20) + { + stream << ", "; + format_rel(stream, pc + 1, opcodes.r8(pc)); + ++pc; + } + } + else if (opcode < 0x34) + { + // MOVL immediate to pointer register + if (BIT(opcode, 0)) + { + util::stream_format(stream, "%s, ", BIT(opcode, 1) ? "yp" : "xp"); + format_imm16(stream, swapendian_int16(opcodes.r16(pc))); + pc += 2; + } + else + stream << "(unknown)"; + } + else if (opcode < 0x3c) + { + // MOV/MOVL direct + if (BIT(opcode, 0)) + { + format_direct(stream, opcodes.r8(pc++)); + stream << ", "; + } + if (opcode < 0x38) + util::stream_format(stream, "(%s)", BIT(opcode, 0) ? "yp" : "xp"); + else if (BIT(opcode, 1)) + stream << "yp"; + else + stream << "xp"; + if (!BIT(opcode, 0)) + { + stream << ", "; + format_direct(stream, opcodes.r8(pc++)); + } + } + else if ((opcode & 0xfe) == 0x44) + { + // CMPM immediate + if (BIT(opcode, 0)) + { + format_direct_masked(stream, opcodes.r8(pc), opcodes.r8(pc + 1)); + pc += 2; + } + else + format_indirect_masked(stream, "xp", opcodes.r8(pc++)); + stream << ", "; + format_imm(stream, opcodes.r8(pc++)); + } + else if (opcode < 0x50 || (opcode & 0xf7) == 0xb5 || (opcode & 0xf7) == 0xc3) + { + // Unary operations + if (BIT(opcode, 0)) + format_direct(stream, opcodes.r8(pc++)); + else + stream << "(xp)"; + } + else if ((opcode & 0xfd) == 0x50) + { + // CMPM with two memory operands + if (BIT(opcode, 1)) + { + u8 da2 = opcodes.r8(pc++); + u8 mask = opcodes.r8(pc++); + format_direct_masked(stream, opcodes.r8(pc++), mask); + stream << ", "; + format_direct_masked(stream, da2, mask); + } + else + { + u8 mask = opcodes.r8(pc++); + format_indirect_masked(stream, "xp", mask); + stream << ", "; + format_indirect_masked(stream, "yp", mask); + } + } + else if ((opcode & 0xf7) == 0x51 || (opcode & 0xf7) == 0xb7) + { + // MUL, DIV, POP, PUSH indirect + stream << "(xp)"; + } + else if (opcode == 0x53) + { + // MOVDA (MN1880 only) + format_direct16(stream, opcodes.r16(pc + 2)); + stream << ", "; + format_direct16(stream, opcodes.r16(pc)); + pc += 4; + } + else if (opcode < 0x80 || (opcode & 0xfd) == 0x84 || (opcode & 0xf4) == 0xc0) + { + // Binary operations + if (BIT(opcode, 1)) + { + // Direct modes + u8 op2 = opcodes.r8(pc++); + format_direct(stream, opcodes.r8(pc++)); + stream << ", "; + if (BIT(opcode, 0)) + { + if (opcode == 0x5f) + format_imm16(stream, op2 | u16(opcodes.r8(pc++)) << 8); + else if ((opcode & 0xf4) == 0x74) + format_imm4(stream, op2); + else + format_imm(stream, op2); + } + else + format_direct(stream, op2); + } + else + { + // Indirect modes + stream << "(xp), "; + if (opcode == 0x5d) + { + format_imm16(stream, swapendian_int16(opcodes.r16(pc))); + pc += 2; + } + else if (BIT(opcode, 0)) + { + if ((opcode & 0xf4) == 0x74) + format_imm4(stream, opcodes.r8(pc++)); + else + format_imm(stream, opcodes.r8(pc++)); + } + else + stream << "(yp)"; + } + } + else if (opcode < 0x90 || (opcode & 0xfc) == 0xe0) + { + if (BIT(opcode, 2)) + { + if (BIT(opcode, 0)) + { + // CLR, SET special flag + if (BIT(opcode, 1)) + stream << "cf"; + else + stream << "df"; + } + else + stream << "(unknown)"; + } + else + { + // Relative branches and loops + if ((opcode & 0xfd) == 0xe1) + util::stream_format(stream, "%s, ", BIT(opcode, 1) ? "yp" : "xp"); + format_rel(stream, pc + 1, opcodes.r8(pc)); + ++pc; + } + } + else if (opcode < 0xb0) + { + // CALL, BR within 4K page + format_abs4k(stream, ((pc + 1) & 0xf000) | u16(opcode & 0x0f) << 8 | opcodes.r8(pc)); + ++pc; + if (opcode < 0xa0) + flags |= STEP_OVER; + } + else if ((opcode & 0xf4) == 0xb0) + { + if (BIT(opcode, 0)) + stream << "fs"; + else + { + // CLR, SET, T1BNZ, T1BZ indirect (MN1870 only) + format_indirect_bp(stream, "xp", opcodes.r8(pc++) & 0x07); + if (BIT(opcode, 1)) + { + stream << ", "; + format_rel(stream, pc + 1, opcodes.r8(pc)); + ++pc; + } + } + } + else if (opcode < 0xc0 || (opcode & 0xfc) == 0xe4 || (opcode & 0xfe) == 0xfc) + { + // PUSH, POP, DEC, INC, BR, CALL pointer + if (BIT(opcode, 1)) + stream << "yp"; + else + stream << "xp"; + if (opcode == 0xfd) + flags |= STEP_OVER; + } + else if (opcode < 0xd0) + { + // XCH, MOV lower half of register + if ((opcode & 0xf5) == 0xc5) + { + util::stream_format(stream, "%sl, ", BIT(opcode, 1) ? "yp" : "xp"); + format_direct(stream, opcodes.r8(pc++)); + } + else if (BIT(opcode, 3)) + { + format_direct(stream, opcodes.r8(pc++)); + util::stream_format(stream, ", %sl", BIT(opcode, 1) ? "yp" : "xp"); + } + else + util::stream_format(stream, "%sl, %sh", BIT(opcode, 1) ? "yp" : "xp", BIT(opcode, 1) ? "yp" : "xp"); + } + else if (opcode < 0xe0) + { + if (BIT(opcode, 2)) + { + // XCH, MOV between pointer registers + if (opcode == 0xd4) + stream << "xp, lp"; + else + { + if (BIT(opcode, 0)) + stream << "xp, "; + if (BIT(opcode, 1)) + stream << "yp"; + else + stream << "sp"; + if (!BIT(opcode, 0)) + stream << ", xp"; + } + } + else + { + // CMP, MOV 8-bit + util::stream_format(stream, "%s%c, ", BIT(opcode, 1) ? "yp" : "xp", (opcode & 0xfd) == 0xd9 ? 'h' : 'l'); + if ((opcode & 0xfd) == 0xd0) + format_direct(stream, opcodes.r8(pc++)); + else + format_imm(stream, opcodes.r8(pc++)); + } + } + else if (opcode < 0xf0) + { + // ADDR + util::stream_format(stream, "%sl, ", BIT(opcode, 1) ? "yp" : "xp"); + if (BIT(opcode, 2)) + { + util::stream_format(stream, "%sl, ", BIT(opcode, 1) ? "yp" : "xp"); + if (BIT(opcode, 0)) + format_imm(stream, opcodes.r8(pc++)); + else + util::stream_format(stream, "%sh", BIT(opcode, 1) ? "yp" : "xp"); + } + else + { + u8 op2 = opcodes.r8(pc++); + format_direct(stream, opcodes.r8(pc++)); + stream << ", "; + if (BIT(opcode, 0)) + format_imm(stream, op2); + else + format_direct(stream, op2); + } + } + else if ((opcode & 0xf6) == 0xf0) + { + // CMPBNE, CMPBE + u8 imm = opcodes.r8(pc++); + if (BIT(opcode, 0)) + format_direct(stream, opcodes.r8(pc++)); + else + stream << "(xp)"; + stream << ", "; + format_imm(stream, imm); + stream << ", "; + format_rel(stream, pc + 1, opcodes.r8(pc)); + ++pc; + } + else if ((opcode & 0xf7) == 0xf2) + { + // MOV1, MOV1N + u8 da2 = opcodes.r8(pc++); + u8 bp = opcodes.r8(pc++); + format_direct_bp(stream, opcodes.r8(pc++), (bp & 0x70) >> 4); + stream << ", "; + format_direct_bp(stream, da2, bp & 0x07); + } + else if (opcode == 0xf3) + { + // WAIT (MN1880 only) + format_imm16(stream, opcodes.r16(pc)); + pc += 2; + } + else if ((opcode & 0xfe) == 0xf6) + { + // BR, CALL absolute + format_abs64k(stream, opcodes.r16(pc)); + pc += 2; + if (BIT(opcode, 0)) + flags |= STEP_OVER; + } + else if (opcode == 0xfb) + { + // PUSH immediate + format_imm(stream, opcodes.r8(pc++)); + } + else if (opcode == 0xfe) + { + // RDTBL + stream << "(xp), (yp)"; + } + else + stream << "(unknown)"; +} + +offs_t mn1880_disassembler::disassemble(std::ostream &stream, offs_t pc, const mn1880_disassembler::data_buffer &opcodes, const mn1880_disassembler::data_buffer ¶ms) +{ + const offs_t pc0 = pc; + offs_t flags = SUPPORTED; + + u8 opcode = opcodes.r8(pc++); + const char *mnemonic = m_inst_names[opcode]; + + u8 rc = 0; + if (REPEAT_COMBINED && mnemonic != nullptr && opcode > 0x00 && opcode < 0x10) + { + rc = opcode; + opcode = opcodes.r8(pc++); + mnemonic = m_inst_names[opcode]; + } + + if (mnemonic == nullptr) + { + util::stream_format(stream, "%-8s", "db"); + format_imm(stream, opcode); + } + else if (opcode == 0x00 || opcode == 0x80) + { + // NOP, SKIP (latter actually executes in immediate mode) + stream << mnemonic; + } + else if (opcode == 0xff) + { + // PI (software interrupt) + stream << mnemonic; + flags |= STEP_OVER; + } + else if ((opcode & 0xfe) == 0xf4) + { + // RET, RETI + stream << mnemonic; + flags |= STEP_OUT; + } + else + { + util::stream_format(stream, "%-8s", mnemonic); + offs_t pc1 = pc; + dasm_operands(stream, opcode, pc, flags, opcodes); + if (REPEAT_COMBINED && rc != 0 && pc1 != pc) + { + do { + stream << ", "; + dasm_operands(stream, opcode, pc, flags, opcodes); + } + while (--rc != 0); + } + } + + if (REPEAT_COMBINED && rc != 0) + util::stream_format(stream, ", rep %d", rc); + + return (pc - pc0) | flags; +} diff --git a/src/devices/cpu/mn1880/mn1880d.h b/src/devices/cpu/mn1880/mn1880d.h new file mode 100644 index 00000000000..453522aa43b --- /dev/null +++ b/src/devices/cpu/mn1880/mn1880d.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_MN1880_MN1880D_H +#define MAME_CPU_MN1880_MN1880D_H + +#pragma once + +class mn1880_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + mn1880_disassembler(); + +protected: + mn1880_disassembler(const char *const *inst_names); + + // disassembler overrides + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + // instruction mnemonic table + static const char *const s_inst_names[256]; + + // internal helpers + void format_direct(std::ostream &stream, u8 da) const; + void format_direct16(std::ostream &stream, u16 da) const; + void format_direct_bp(std::ostream &stream, u8 da, u8 bp) const; + void format_indirect_bp(std::ostream &stream, const char *ptr, u8 bp) const; + void format_direct_masked(std::ostream &stream, u8 da, u8 mask) const; + void format_indirect_masked(std::ostream &stream, const char *ptr, u8 mask) const; + void format_imm(std::ostream &stream, u8 imm) const; + void format_imm4(std::ostream &stream, u8 imm) const; + void format_imm16(std::ostream &stream, u16 imm) const; + void format_rel(std::ostream &stream, u16 base, s8 disp) const; + void format_abs4k(std::ostream &stream, u16 label) const; + void format_abs64k(std::ostream &stream, u16 label) const; + void dasm_operands(std::ostream &stream, u8 opcode, offs_t &pc, offs_t &flags, const data_buffer &opcodes); + + const char *const *m_inst_names; +}; + +class mn1870_disassembler : public mn1880_disassembler +{ +public: + // construction/destruction + mn1870_disassembler(); + +private: + // instruction mnemonic table + static const char *const s_inst_names[256]; +}; + +#endif // MAME_CPU_PIC17_PIC17D_H |