summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2019-11-18 18:15:09 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2019-11-18 18:15:09 +0700
commitf821d80e01b86ca31dcd90e63550537158361ee6 (patch)
treedf7463de0a024e9d68f45efcb4c3d6f65ff0edec /src/devices
parent5e8dad836af986d5784a6f2a04eb0c7329651afa (diff)
dsp56000: new disassembler
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/cpu/dsp56000/dsp56000.cpp89
-rw-r--r--src/devices/cpu/dsp56000/dsp56000.h59
-rw-r--r--src/devices/cpu/dsp56000/dsp56000d.cpp744
-rw-r--r--src/devices/cpu/dsp56000/dsp56000d.h25
4 files changed, 917 insertions, 0 deletions
diff --git a/src/devices/cpu/dsp56000/dsp56000.cpp b/src/devices/cpu/dsp56000/dsp56000.cpp
new file mode 100644
index 00000000000..f9ee7c9d4a3
--- /dev/null
+++ b/src/devices/cpu/dsp56000/dsp56000.cpp
@@ -0,0 +1,89 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * An emulation of the Motorola DSP56000/DSP56001.
+ *
+ * Sources:
+ * - http://www.bitsavers.org/components/motorola/56000/1990_DSP56000_DSP56001_Users_Manual.pdf
+ *
+ * TODO:
+ * - emulation
+ */
+
+#include "emu.h"
+#include "debugger.h"
+#include "dsp56000.h"
+#include "dsp56000d.h"
+
+#define LOG_GENERAL (1U << 0)
+
+//#define VERBOSE (LOG_GENERAL)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(DSP56000, dsp56000_device, "dsp56000", "Motorola DSP56000")
+DEFINE_DEVICE_TYPE(DSP56001, dsp56001_device, "dsp56001", "Motorola DSP56001")
+
+dsp56000_device_base::dsp56000_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock)
+ : cpu_device(mconfig, type, tag, owner, clock)
+ , m_p_config("p", ENDIANNESS_BIG, 32, 16, -2)
+ , m_x_config("x", ENDIANNESS_BIG, 32, 16, -2)
+ , m_y_config("y", ENDIANNESS_BIG, 32, 16, -2)
+ , m_icount(0)
+{
+}
+
+dsp56000_device::dsp56000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : dsp56000_device_base(mconfig, DSP56000, tag, owner, clock)
+{
+}
+
+dsp56001_device::dsp56001_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : dsp56000_device_base(mconfig, DSP56001, tag, owner, clock)
+{
+}
+
+void dsp56000_device_base::device_start()
+{
+ // program-visible cpu state
+ save_item(NAME(m_pc));
+
+ state_add(STATE_GENPC, "GENPC", m_pc).noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow();
+
+ set_icountptr(m_icount);
+}
+
+void dsp56000_device_base::device_reset()
+{
+ m_pc = 0;
+}
+
+void dsp56000_device_base::execute_run()
+{
+ while (m_icount > 0)
+ {
+ debugger_instruction_hook(m_pc);
+
+ m_icount = 0;
+ }
+}
+
+void dsp56000_device_base::execute_set_input(int inputnum, int state)
+{
+}
+
+device_memory_interface::space_config_vector dsp56000_device_base::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_p_config),
+ std::make_pair(1, &m_x_config),
+ std::make_pair(2, &m_y_config)
+ };
+}
+
+std::unique_ptr<util::disasm_interface> dsp56000_device_base::create_disassembler()
+{
+ return std::make_unique<dsp56000_disassembler>();
+}
diff --git a/src/devices/cpu/dsp56000/dsp56000.h b/src/devices/cpu/dsp56000/dsp56000.h
new file mode 100644
index 00000000000..0a47b2fe078
--- /dev/null
+++ b/src/devices/cpu/dsp56000/dsp56000.h
@@ -0,0 +1,59 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_CPU_DSP56000_DSP56000_H
+#define MAME_CPU_DSP56000_DSP56000_H
+
+#pragma once
+
+class dsp56000_device_base : public cpu_device
+{
+protected:
+ dsp56000_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
+
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_execute_interface overrides
+ virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 2 - 1) / 2; }
+ virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 2); }
+ virtual u32 execute_min_cycles() const noexcept override { return 1; }
+ virtual u32 execute_max_cycles() const noexcept override { return 16; }
+ virtual u32 execute_input_lines() const noexcept override { return 2; }
+ virtual void execute_run() override;
+ virtual void execute_set_input(int inputnum, int state) override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_disasm_interface overrides
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+
+ // emulation state
+ address_space_config m_p_config;
+ address_space_config m_x_config;
+ address_space_config m_y_config;
+
+ int m_icount;
+
+ // program-visible cpu state
+ u16 m_pc;
+};
+
+class dsp56000_device : public dsp56000_device_base
+{
+public:
+ dsp56000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+};
+
+class dsp56001_device : public dsp56000_device_base
+{
+public:
+ dsp56001_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+};
+
+DECLARE_DEVICE_TYPE(DSP56000, dsp56000_device)
+DECLARE_DEVICE_TYPE(DSP56001, dsp56001_device)
+
+#endif // MAME_CPU_DSP56000_DSP56000_H
diff --git a/src/devices/cpu/dsp56000/dsp56000d.cpp b/src/devices/cpu/dsp56000/dsp56000d.cpp
new file mode 100644
index 00000000000..d4eca19f3c6
--- /dev/null
+++ b/src/devices/cpu/dsp56000/dsp56000d.cpp
@@ -0,0 +1,744 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#include "emu.h"
+#include "dsp56000d.h"
+
+static char const* const CCCC[] =
+{
+ "cc", "ge", "ne", "pl", "nn", "ec", "lc", "gt",
+ "cs", "lt", "eq", "mi", "nr", "es", "ls", "le",
+};
+
+static char const* const JJD[] =
+{
+ "x0,a", "x0,b", "y0,a", "y0,b", "x1,a", "x1,b", "y1,a", "y1,b",
+};
+
+static char const* const JJJD[] =
+{
+ "b,a", "a,b", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ "x0,a", "x0,b", "y0,a", "y0,b", "x1,a", "x1,b", "y1,a", "y1,b",
+};
+
+static char const* const EE[] =
+{
+ "mr", "ccr", "omr", nullptr,
+};
+
+static char const* const DD[] = { "x0", "x1", "y0", "y1" };
+static char const* const ee[] = { "x0", "x1", "a", "b" };
+static char const* const ff[] = { "y0", "y1", "a", "b" };
+
+static char const* const DDD[] = { "a0", "b0", "a2", "b2", "a1", "b1", "a", "b" };
+static char const* const LLL[] = { "a10", "b10", "x", "y", "a", "b", "ab", "ba" };
+static char const* const FFF[] = { "m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7" };
+static char const* const NNN[] = { "n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7" };
+static char const* const TTT[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" };
+static char const* const GGG[] = { nullptr, "sr", "omr", "sp", "ssh", "ssl", "la", "lc" };
+
+static char const* const QQQ[] = { "x0,x0", "y0,y0", "x1,x0", "y1,y0", "x0,y1", "y0,x0", "x1,y0", "y1,x1" };
+
+static char const* const NIE[][8] =
+{
+ { "move", "tfr", "addr", "tst", "*", "cmp", "subr", "cmpm" },
+ { "add", "rnd", "addl", "clr", "sub", "*", "subl", "not" },
+ { "add", "adc", "asr", "lsr", "sub", "sbc", "abs", "ror" },
+ { "add", "adc", "asl", "lsl", "sub", "sbc", "neg", "rol" },
+ { "add", "tfr", "or", "eor", "sub", "cmp", "and", "cmpm" },
+ { "add", "tfr", "or", "eor", "sub", "cmp", "and", "cmpm" },
+ { "add", "tfr", "or", "eor", "sub", "cmp", "and", "cmpm" },
+ { "add", "tfr", "or", "eor", "sub", "cmp", "and", "cmpm" },
+};
+
+offs_t dsp56000_disassembler::disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const &params)
+{
+ u32 flags = SUPPORTED;
+ unsigned words = 0;
+
+ // fetch the instruction word and consume it
+ u32 const op = opcodes.r32(pc + words++) & 0x00ffffffU;
+
+ // fetch the extension word but don't consume it yet
+ u32 const ew = opcodes.r32(pc + words) & 0x00ffffffU;
+
+ /*
+ * Special-case test for X:R and R:Y class II data moves which also have
+ * four most significant bits zero.
+ */
+ if (!(op >> 20) && (op & 0x0e4000U) != 0x080000U)
+ {
+ /*
+ * Instructions which do not allow parallel moves:
+ *
+ * 0000 1111 CCCC aaaa aaaa aaaa JScc xxx
+ * 0000 1110 CCCC aaaa aaaa aaaa Jcc xxx
+ * 0000 1101 0000 aaaa aaaa aaaa JSR xxx
+ * 0000 1100 0000 aaaa aaaa aaaa JMP xxx
+ *
+ * 0000 1011 10pp pppp 1S1b bbbb+ JSSET #n,X:pp,xxxx
+ * 0000 1011 10pp pppp 1S0b bbbb+ JSCLR #n,X:pp,xxxx
+ * 0000 1010 10pp pppp 1S1b bbbb+ JSET #n,X:pp,xxxx
+ * 0000 1010 10pp pppp 1S0b bbbb+ JCLR #n,X:pp,xxxx
+ * 0000 1011 10pp pppp 0S1b bbbb BTST #n,X:pp
+ * 0000 1011 10pp pppp 0S0b bbbb BCHG #n,X:pp
+ * 0000 1010 10pp pppp 0S1b bbbb BSET #n,X:pp
+ * 0000 1010 10pp pppp 0S0b bbbb BCLR #n,X:pp
+ *
+ * 0000 1011 01MM MRRR 1S1b bbbb+ JSSET #n,X:ea,xxxx
+ * 0000 1011 01MM MRRR 1S0b bbbb+ JSCLR #n,X:ea,xxxx
+ * 0000 1010 01MM MRRR 1S1b bbbb+ JSET #n,X:ea,xxxx
+ * 0000 1010 01MM MRRR 1S0b bbbb+ JCLR #n,X:ea,xxxx
+ * 0000 1011 01MM MRRR 0S1b bbbb BTST #n,X:ea
+ * 0000 1011 01MM MRRR 0S0b bbbb BCHG #n,X:ea
+ * 0000 1010 01MM MRRR 0S1b bbbb BSET #n,X:ea
+ * 0000 1010 01MM MRRR 0S0b bbbb BCLR #n,X:ea
+ *
+ * 0000 1011 00aa aaaa 1S1b bbbb+ JSSET #n,X:aa,xxxx
+ * 0000 1011 00aa aaaa 1S0b bbbb+ JSCLR #n,X:aa,xxxx
+ * 0000 1010 00aa aaaa 1S1b bbbb+ JSET #n,X:aa,xxxx
+ * 0000 1010 00aa aaaa 1S0b bbbb+ JCLR #n,X:aa,xxxx
+ * 0000 1011 00aa aaaa 0S1b bbbb BTST #n,X:aa
+ * 0000 1011 00aa aaaa 0S0b bbbb BCHG #n,X:aa
+ * 0000 1010 00aa aaaa 0S1b bbbb BSET #n,X:aa
+ * 0000 1010 00aa aaaa 0S0b bbbb BCLR #n,X:aa
+ *
+ * 0000 1011 11dd dddd 001b bbbb+ JSSET #n,S,xxxx
+ * 0000 1011 11dd dddd 000b bbbb+ JSCLR #n,S,xxxx
+ * 0000 1010 11dd dddd 001b bbbb+ JSET #n,S,xxxx
+ * 0000 1010 11dd dddd 000b bbbb+ JCLR #n,S,xxxx
+ * 0000 1011 11dd dddd 011b bbbb BTST #n,D
+ * 0000 1011 11dd dddd 010b bbbb BCHG #n,D
+ * 0000 1010 11dd dddd 011b bbbb BSET #n,D
+ * 0000 1010 11dd dddd 010b bbbb BCLR #n,D
+ *
+ * 0000 1011 11MM MRRR 1010 CCCC+ JScc ea
+ * 0000 1011 11MM MRRR 1000 0000+ JSR ea
+ * 0000 1010 11MM MRRR 1010 CCCC+ Jcc ea
+ * 0000 1010 11MM MRRR 1000 0000+ JMP ea
+ *
+ * 0000 100s W1MM MRRR 1Spp pppp+ MOVEP
+ * 0000 100S W1MM MRRR 01pp pppp+ MOVEP
+ * 0000 100S W1dd dddd 00pp pppp MOVEP
+ *
+ * 0000 0111 W1MM MRRR 10dd dddd+ MOVE(M)
+ * 0000 0111 W0aa aaaa 00dd dddd MOVE(M)
+ *
+ * 0000 0110 iiii iiii 1010 hhhh REP #xxx
+ * 0000 0110 11dd dddd 0010 0000 REP S
+ * 0000 0110 01MM MRRR 0s10 0000 REP X:ea
+ * 0000 0110 00aa aaaa 0s10 0000 REP X:aa
+ * 0000 0110 iiii iiii 1000 hhhh+ DO #xxx,expr
+ * 0000 0110 11DD DDDD 0000 0000+ DO S,expr
+ * 0000 0110 01MM MRRR 0S00 0000+ DO X:ea,expr
+ * 0000 0110 00aa aaaa 0S00 0000+ DO X:aa,expr
+ *
+ * 0000 0101 iiii iiii 101d dddd MOVE(C) #xx,D1
+ * 0000 0101 W1MM MRRR 0s1d dddd+ MOVE(C)
+ * 0000 0101 W0aa aaaa 0s1d dddd MOVE(C)
+ *
+ * 0000 0100 W1ee eeee 101d dddd MOVE(C) S1,D1
+ * 0000 0100 010M MRRR 0001 dddd LUA ea,D
+ *
+ * 0000 0011 CCCC 0ttt 0JJJ DTTT Tcc S1,D1 S2,D2
+ *
+ * 0000 0010 CCCC 0000 0JJJ D000 Tcc S1,D1
+ *
+ * 0000 0001 1101 1RRR 0001 d101 NORM Rn,D
+ * 0000 0001 1000 0000 01JJ d000 DIV S,D
+ *
+ * 0000 0000 iiii iiii 1111 10EE OR(I) #xx,D
+ * 0000 0000 iiii iiii 1011 10EE AND(I) #xx,D
+ * 0000 0000 0000 0000 1000 1100 ENDDO
+ * 0000 0000 0000 0000 1000 0111 STOP
+ * 0000 0000 0000 0000 1000 0110 WAIT
+ * 0000 0000 0000 0000 1000 0100 RESET
+ * 0000 0000 0000 0000 0000 1100 RTS
+ * 0000 0000 0000 0000 0000 0110 SWI
+ * 0000 0000 0000 0000 0000 0101 ILLEGAL
+ * 0000 0000 0000 0000 0000 0100 RTI
+ * 0000 0000 0000 0000 0000 0000 NOP
+ */
+ switch ((op >> 16) & 15)
+ {
+ case 0x0:
+ switch (op & 0xff)
+ {
+ case 0x00: util::stream_format(stream, "nop"); break;
+ case 0x04: util::stream_format(stream, "rti"); flags |= STEP_OUT; break;
+ case 0x05: util::stream_format(stream, "illegal"); break;
+ case 0x06: util::stream_format(stream, "swi"); break;
+ case 0x0c: util::stream_format(stream, "rts"); flags |= STEP_OUT; break;
+ case 0x84: util::stream_format(stream, "reset"); break;
+ case 0x86: util::stream_format(stream, "wait"); break;
+ case 0x87: util::stream_format(stream, "stop"); break;
+ case 0x8c: util::stream_format(stream, "enddo"); break;
+
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ util::stream_format(stream, "ori #$%x,%s", u8(op >> 8), EE[op & 3]);
+ break;
+
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ util::stream_format(stream, "andi #$%x,%s", u8(op >> 8), EE[op & 3]);
+ break;
+ }
+ break;
+ case 0x1:
+ switch (op & 0x00f8c7U)
+ {
+ case 0x008040U: util::stream_format(stream, "div %s", JJD[(op >> 3) & 7]); break;
+ case 0x00d805U: util::stream_format(stream, "norm r%d,%c", (op >> 8) & 7, BIT(op, 3) ? 'B' : 'A'); break;
+ }
+ break;
+ case 0x2: util::stream_format(stream, "t%s %s", CCCC[(op >> 12) & 15], JJJD[(op >> 3) & 7]); break;
+ case 0x3: util::stream_format(stream, "t%s %s r%d,r%d", CCCC[(op >> 12) & 15], JJJD[(op >> 3) & 7], (op >> 8) & 7, op & 7); break;
+ case 0x4:
+ switch (op & 0x0000e0U)
+ {
+ case 0x000000U: util::stream_format(stream, "lua %s,%s", ea((op >> 8) & 31), reg(op & 31)); break;
+ case 0x0000a0U:
+ if (BIT(op, 15))
+ util::stream_format(stream, "%-16s%s,%s", "movec", reg((op >> 8) & 63), reg(op & 63));
+ else
+ util::stream_format(stream, "%-16s%s,%s", "movec", reg(op & 63), reg((op >> 8) & 63));
+ break;
+ }
+ break;
+ case 0x5:
+ if (BIT(op, 7))
+ {
+ // move control register (immediate short)
+ util::stream_format(stream, "%-16s#<$%x,%s", "movec", u8(op >> 8), reg(op & 63));
+ }
+ else if (BIT(op, 14))
+ {
+ // move control register (effective address)
+ char const S = BIT(op, 6) ? 'y' : 'x';
+ unsigned const MMMRRR = (op >> 8) & 63;
+
+ if (BIT(op, 15))
+ if (MMMRRR == 0x34)
+ util::stream_format(stream, "%-16s#$%x,%s", "movec", u16(ew), reg(op & 63));
+ else
+ util::stream_format(stream, "%-16s%c:%s,%s", "movec", S, ea(MMMRRR, ew), reg(op & 63));
+ else
+ util::stream_format(stream, "%-16s%s,%c:%s", "movec", reg(op & 63), S, ea(MMMRRR, ew));
+
+ // consume immediate or absolute
+ if ((MMMRRR >> 3) == 6)
+ words++;
+ }
+ else
+ {
+ // move control register (absolute short)
+ u16 const aa = (op >> 8) & 63;
+ char const S = BIT(op, 6) ? 'y' : 'x';
+
+ if (BIT(op, 15))
+ util::stream_format(stream, "%-16s%c:<$%x,%s", "movec", S, aa, reg(op & 63));
+ else
+ util::stream_format(stream, "%-16s%s,%c:<$%x", "movec", reg(op & 63), S, aa);
+ }
+ break;
+ case 0x6:
+ if (BIT(op, 5))
+ // repeat next instruction
+ util::stream_format(stream, "rep ");
+ else
+ // start hardware loop
+ util::stream_format(stream, "do ");
+
+ if (BIT(op, 7))
+ {
+ // immediate short
+ u16 const count = (op & 15) << 8 | u8(op >> 8);
+
+ util::stream_format(stream, "#$%x", count);
+ }
+ else
+ {
+ char const s = BIT(op, 6) ? 'y' : 'x';
+ unsigned const constant = (op >> 8) & 63;
+
+ switch (op & 0x00c000U)
+ {
+ case 0x000000U: util::stream_format(stream, "%c:<$%x", s, constant); break;
+ case 0x004000U: util::stream_format(stream, "%c:%s", s, ea(constant)); break;
+ case 0x00c000U: util::stream_format(stream, "%s", reg(constant)); break;
+ }
+ }
+
+ // append expr and consume extension word
+ if (!BIT(op, 5))
+ {
+ util::stream_format(stream, ",$%x", u16(ew));
+ words++;
+ }
+ break;
+ case 0x7:
+ if (BIT(op, 7))
+ {
+ // move program memory (effective address)
+ unsigned const MMMRRR = (op >> 8) & 63;
+
+ if (BIT(op, 15))
+ util::stream_format(stream, "%-16sp:%s,%s", "movem", ea(MMMRRR, ew), reg(op & 63));
+ else
+ util::stream_format(stream, "%-16s%s,p:%s", "movem", reg(op & 63), ea(MMMRRR, ew));
+
+ // consume absolute
+ if ((MMMRRR >> 3) == 6)
+ words++;
+ }
+ else
+ {
+ // move program memory (absolute short)
+ u16 const aa = (op >> 8) & 63;
+
+ if (BIT(op, 15))
+ util::stream_format(stream, "%-16sp:<$%x,%s", "movem", aa, reg(op & 63));
+ else
+ util::stream_format(stream, "%-16s%s,p:<$%x", "movem", reg(op & 63), aa);
+ }
+ break;
+ case 0x8:
+ case 0x9:
+ {
+ u16 const pp = 0xffc0 | ((op >> 8) & 63);
+
+ if (BIT(op, 7))
+ {
+ // move peripheral data (X or Y reference)
+ char const S = BIT(op, 6) ? 'y' : 'x';
+ unsigned const MMMRRR = (op >> 8) & 63;
+ char const s = BIT(op, 16) ? 'y' : 'x';
+
+ if (BIT(op, 15))
+ if (MMMRRR == 0x34)
+ util::stream_format(stream, "%-16s#$%x,%c:<<$%x", "movep", ew, s, pp);
+ else
+ util::stream_format(stream, "%-16s%c:%s,%c:<<$%x", "movep", S, ea(MMMRRR, ew), s, pp);
+ else
+ util::stream_format(stream, "%-16s%c:<<$%x,%c:%s", "movep", s, pp, S, ea(MMMRRR, ew));
+
+ // consume immediate or absolute
+ if ((MMMRRR >> 3) == 6)
+ words++;
+ }
+ else if (BIT(op, 6))
+ {
+ // move peripheral data (P reference)
+ unsigned const MMMRRR = (op >> 8) & 63;
+ char const S = BIT(op, 6) ? 'y' : 'x';
+
+ if (BIT(op, 15))
+ util::stream_format(stream, "%-16sp:%s,%c:<<$%x", "movep", ea(MMMRRR, ew), S, pp);
+ else
+ util::stream_format(stream, "%-16s%c:<<$%x,p:%s", "movep", S, pp, ea(MMMRRR, ew));
+
+ // consume absolute
+ if ((MMMRRR >> 3) == 6)
+ words++;
+ }
+ else
+ {
+ // move peripheral data (register)
+ char const S = BIT(op, 16) ? 'y' : 'x';
+ unsigned const dddddd = (op >> 8) & 63;
+
+ if (BIT(op, 15))
+ util::stream_format(stream, "%-16s%s,%c:<<$%x", "movep", reg(dddddd), S, pp);
+ else
+ util::stream_format(stream, "%-16s%c:<<$%x,%s", "movep", S, pp, reg(dddddd));
+ }
+ }
+ break;
+ case 0xa:
+ case 0xb:
+ if ((op & 0x00c000U) == 0x00c000U)
+ {
+ if (BIT(op, 7))
+ {
+ // branches (effective address)
+ unsigned const MMMRRR = (op >> 8) & 63;
+
+ switch (op & 0x010020U)
+ {
+ case 0x000000U: util::stream_format(stream, "jmp %s", ea(MMMRRR, ew)); break;
+ case 0x000020U: util::stream_format(stream, "j%s %s", CCCC[op & 15], ea(MMMRRR, ew)); break;
+ case 0x010000U: util::stream_format(stream, "jsr %s", ea(MMMRRR, ew)); break;
+ case 0x010020U: util::stream_format(stream, "js%s %s", CCCC[op & 15], ea(MMMRRR, ew)); break;
+ }
+
+ // consume absolute
+ if ((MMMRRR >> 3) == 6)
+ words++;
+ }
+ else
+ {
+ // bit operations (register)
+ unsigned const dddddd = (op >> 8) & 63;
+
+ switch (op & 0x010060U)
+ {
+ case 0x000000U: util::stream_format(stream, "jclr #%d,%s,$%x", op & 31, reg(dddddd), u16(ew)); words++; break;
+ case 0x000020U: util::stream_format(stream, "jset #%d,%s,$%x", op & 31, reg(dddddd), u16(ew)); words++; break;
+ case 0x000040U: util::stream_format(stream, "bclr #%d,%s", op & 31, reg(dddddd)); break;
+ case 0x000060U: util::stream_format(stream, "bset #%d,%s", op & 31, reg(dddddd)); break;
+ case 0x010000U: util::stream_format(stream, "jsclr #%d,%s,$%x", op & 31, reg(dddddd), u16(ew)); words++; break;
+ case 0x010020U: util::stream_format(stream, "jsset #%d,%s,$%x", op & 31, reg(dddddd), u16(ew)); words++; break;
+ case 0x010040U: util::stream_format(stream, "bchg #%d,%s", op & 31, reg(dddddd)); break;
+ case 0x010060U: util::stream_format(stream, "btst #%d,%s", op & 31, reg(dddddd)); break;
+ }
+ }
+ }
+ else
+ {
+ // bit operations (memory)
+
+ // opcode and bit number
+ switch (op & 0x0100a0U)
+ {
+ case 0x000000U: util::stream_format(stream, "bclr #%d", op & 31); break;
+ case 0x000020U: util::stream_format(stream, "bset #%d", op & 31); break;
+ case 0x000080U: util::stream_format(stream, "jclr #%d", op & 31); break;
+ case 0x0000a0U: util::stream_format(stream, "jset #%d", op & 31); break;
+ case 0x010000U: util::stream_format(stream, "bchg #%d", op & 31); break;
+ case 0x010020U: util::stream_format(stream, "btst #%d", op & 31); break;
+ case 0x010080U: util::stream_format(stream, "jsclr #%d", op & 31); break;
+ case 0x0100a0U: util::stream_format(stream, "jsset #%d", op & 31); break;
+ }
+
+ // second operand (address)
+ char const S = BIT(op, 6) ? 'y' : 'x';
+ unsigned const constant = (op >> 8) & 63;
+ switch (op & 0x00c000U)
+ {
+ case 0x000000U: util::stream_format(stream, ",%c:<$%x", S, constant); break;
+ case 0x004000U: util::stream_format(stream, ",%c:%s", S, ea(constant)); break;
+ case 0x008000U: util::stream_format(stream, ",%c:<<$%x", S, u16(0xffc0 | constant)); break;
+ }
+
+ // branch target
+ if (BIT(op, 7))
+ {
+ util::stream_format(stream, ",$%x", u16(ew));
+ words++;
+ }
+ }
+ break;
+ case 0xc: util::stream_format(stream, "jmp <$%x", op & 0xfff); break;
+ case 0xd: util::stream_format(stream, "jsr <$%x", op & 0xfff); break;
+ case 0xe: util::stream_format(stream, "j%s <$%x", CCCC[(op >> 12) & 15], op & 0xfff); break;
+ case 0xf: util::stream_format(stream, "js%s <$%x", CCCC[(op >> 12) & 15], op & 0xfff); break;
+ }
+ }
+ else
+ {
+ std::string alu;
+
+ if (BIT(op, 7))
+ {
+ // multiply instructions
+ // 1QQQ dkkk
+ char const d = BIT(op, 3) ? 'b' : 'a';
+
+ switch (op & 7)
+ {
+ case 0: alu = util::string_format("mpy %s,%c", QQQ[(op >> 4) & 7], d); break;
+ case 1: alu = util::string_format("mpyr %s,%c", QQQ[(op >> 4) & 7], d); break;
+ case 2: alu = util::string_format("mac %s,%c", QQQ[(op >> 4) & 7], d); break;
+ case 3: alu = util::string_format("macr %s,%c", QQQ[(op >> 4) & 7], d); break;
+ case 4: alu = util::string_format("mpy -%s,%c", QQQ[(op >> 4) & 7], d); break;
+ case 5: alu = util::string_format("mpyr -%s,%c", QQQ[(op >> 4) & 7], d); break;
+ case 6: alu = util::string_format("mac -%s,%c", QQQ[(op >> 4) & 7], d); break;
+ case 7: alu = util::string_format("macr -%s,%c", QQQ[(op >> 4) & 7], d); break;
+ }
+ }
+ else
+ {
+ // non-multiply instructions
+ // 0JJJ Dkkk
+ unsigned const JJJ = (op >> 4) & 7;
+ char const D = BIT(op, 3) ? 'b' : 'a';
+
+ switch (JJJ)
+ {
+ case 0:
+
+ switch (op & 15)
+ {
+ case 0:
+ alu = "move";
+ break;
+ case 8:
+ // special case #1
+ break;
+ default:
+ alu = util::string_format("%-5s %c", NIE[JJJ][op & 7], D);
+ break;
+ }
+ break;
+ case 1: alu = util::string_format("%-5s %c", NIE[JJJ][op & 7], D); break;
+ case 2:
+ // special case #2
+ if (BIT(op, 1))
+ alu = util::string_format("%-5s %c", NIE[JJJ][op & 7], D);
+ else
+ alu = util::string_format("%-5s x1x0,%c", NIE[JJJ][op & 7], D);
+ break;
+ case 3:
+ // special case #2
+ if (BIT(op, 1))
+ alu = util::string_format("%-5s %c", NIE[JJJ][op & 7], D);
+ else
+ alu = util::string_format("%-5s y1y0,%c", NIE[JJJ][op & 7], D);
+ break;
+ case 4: alu = util::string_format("%-5s x0_0,%c", NIE[JJJ][op & 7], D); break;
+ case 5: alu = util::string_format("%-5s y0_0,%c", NIE[JJJ][op & 7], D); break;
+ case 6: alu = util::string_format("%-5s x1_0,%c", NIE[JJJ][op & 7], D); break;
+ case 7: alu = util::string_format("%-5s y1_0,%c", NIE[JJJ][op & 7], D); break;
+ }
+ }
+
+ util::stream_format(stream, "%-16s", alu);
+
+ if (BIT(op, 23))
+ {
+ // XY memory data move
+ // 1Wmm eeff WrrM MRRR OPER CODE
+ unsigned const eax = (op & 0x001800U) ? (op >> 8) & 31 : ((op >> 8) & 31) | 32;
+ unsigned const eay = eax ^ 4;
+
+ std::string x;
+ std::string y;
+
+ if (BIT(op, 15))
+ x = util::string_format("x:%s,%s", ea(eax), ee[(op >> 18) & 3]);
+ else
+ x = util::string_format("%s,x:%s", ee[(op >> 18) & 3], ea(eax));
+
+ if (BIT(op, 22))
+ y = util::string_format("y:%s,%s", ea(eay), ff[(op >> 16) & 3]);
+ else
+ y = util::string_format("%s,y:%s", ff[(op >> 16) & 3], ea(eay));
+
+ util::stream_format(stream, "%-16s%s", x, y);
+ }
+ else if (BIT(op, 22))
+ {
+ bool const W = BIT(op, 15);
+ unsigned const constant = (op >> 8) & 63;
+
+ if (op & 0x340000U)
+ {
+ // X memory data move
+ // 01dd 0ddd W1MM MRRR OPER CODE+
+ // 01dd 0ddd W0aa aaaa OPER CODE
+
+ // Y memory data move
+ // 01dd 1ddd W1MM MRRR OPER CODE+
+ // 01dd 1ddd W0aa aaaa OPER CODE
+
+ char const S = BIT(op, 19) ? 'y' : 'x';
+ std::string const r = reg(((op >> 17) & 0x18) | ((op >> 16) & 7));
+
+ if (BIT(op, 14))
+ {
+ // effective address
+ if (W)
+ if (constant == 0x34)
+ util::stream_format(stream, "#$%x,%s", ew, r);
+ else
+ util::stream_format(stream, "%c:%s,%s", S, ea(constant, ew), r);
+ else
+ util::stream_format(stream, "%s,%c:%s", r, S, ea(constant, ew));
+
+ // consume immediate or absolute
+ if ((constant >> 3) == 6)
+ words++;
+ }
+ else
+ {
+ // absolute short
+ if (W)
+ util::stream_format(stream, "%c:<$%x,%s", S, constant, r);
+ else
+ util::stream_format(stream, "%s,%c:<$%x", r, S, constant);
+ }
+ }
+ else
+ {
+ // long memory data move
+ // 0100 L0LL W1MM MRRR OPER CODE+
+ // 0100 L0LL W0aa aaaa OPER CODE
+
+ char const *const r = LLL[((op >> 17) & 0x4) | ((op >> 16) & 3)];
+
+ if (BIT(op, 14))
+ {
+ // effective address
+ if (W)
+ util::stream_format(stream, "l:%s,%s", ea(constant, ew), r);
+ else
+ util::stream_format(stream, "%s,l:%s", r, ea(constant, ew));
+
+ // consume absolute
+ if ((constant >> 3) == 6)
+ words++;
+ }
+ else
+ {
+ // absolute short
+ if (W)
+ util::stream_format(stream, "l:<$%x,%s", constant, r);
+ else
+ util::stream_format(stream, "%s,l:<$%x", r, constant);
+ }
+ }
+ }
+ else if (BIT(op, 21))
+ {
+ if (op & 0x1c0000U)
+ {
+ // immediate short data move
+ // 001d dddd iiii iiii OPER CODE
+
+ util::stream_format(stream, "#<$%x,%s", u8(op >> 8), reg((op >> 16) & 31));
+ }
+ else
+ switch (op & 0x03e000U)
+ {
+ case 0x000000U:
+ // no parallel data move
+ // 0010 0000 0000 0000 OPER CODE
+ break;
+
+ case 0x004000U:
+ // address register update
+ // 0010 0000 010M MRRR OPER CODE
+ util::stream_format(stream, "%s", ea((op >> 8) & 31));
+ break;
+
+ default:
+ // register to register data move
+ // 0010 00ee eeed dddd OPER CODE
+ util::stream_format(stream, "%s,%s", reg((op >> 13) & 31), reg((op >> 8) & 31));
+ break;
+ }
+ }
+ else if (BIT(op, 20))
+ {
+ unsigned const MMMRRR = (op >> 8) & 63;
+
+ if (BIT(op, 14))
+ {
+ // register and Y memory data move (class I)
+ // 0001 deff W1MM MRRR OPER CODE+
+
+ // S1,D1
+ std::string const op1 = util::string_format("%c,%s", BIT(op, 19) ? 'b' : 'a', BIT(op, 18) ? "x1" : "x0");
+
+ if (BIT(op, 15))
+ if (MMMRRR == 0x34)
+ util::stream_format(stream, "%-16s#$%x,%s", op1, ew, ff[(op >> 16) & 3]);
+ else
+ util::stream_format(stream, "%-16sy:%s,%s", op1, ea(MMMRRR, ew), ff[(op >> 16) & 3]);
+ else
+ util::stream_format(stream, "%-16s%s,y:%s", op1, ff[(op >> 16) & 3], ea(MMMRRR, ew));
+ }
+ else
+ {
+ // X memory and register data move (class I)
+ // 0001 ffdf W0MM MRRR OPER CODE+
+
+ // TODO: documentation shows ff for S1,D1 but should be ee
+ std::string op1;
+
+ if (BIT(op, 15))
+ if (MMMRRR == 0x34)
+ op1 = util::string_format("#$%x,%s", ew, ee[(op >> 18) & 3]);
+ else
+ op1 = util::string_format("x:%s,%s", ea(MMMRRR, ew), ee[(op >> 18) & 3]);
+ else
+ op1 = util::string_format("%s,x:%s", ee[(op >> 18) & 3], ea(MMMRRR, ew));
+
+ // S2,D2
+ util::stream_format(stream, "%-16s%c,%s", op1, BIT(op, 17) ? 'b' : 'a', BIT(op, 16) ? "y1" : "y0");
+ }
+
+ // consume immediate or absolute
+ if ((MMMRRR >> 3) == 6)
+ words++;
+ }
+ else
+ {
+ // TODO: documentation states long absolute and long immediate are
+ // excluded but shows optional effective address extension word and
+ // includes those effective addressing modes in the list?
+
+ char const d = BIT(op, 16) ? 'b' : 'a';
+ unsigned const MMMRRR = (op >> 8) & 63;
+
+ if (BIT(op, 15))
+ {
+ // register and Y memory data move (class II)
+ // 0000 100d 10MM MRRR OPER CODE +
+
+ std::string const op1 = string_format("y0,%c", d);
+ util::stream_format(stream, "%-16s%c,y:%s", op1, d, ea(MMMRRR));
+ }
+ else
+ {
+ // X memory and register data move (class II)
+ // 0000 100d 00MM RRRR OPER CODE +
+
+ std::string const op1 = util::string_format("%c,x:%s", d, ea(MMMRRR));
+ util::stream_format(stream, "%-16sx0,%c", op1, d);
+ }
+ }
+ }
+
+ return words | flags;
+}
+
+std::string dsp56000_disassembler::reg(unsigned const dddddd) const
+{
+ switch (dddddd >> 3)
+ {
+ case 0:
+ if (BIT(dddddd, 2))
+ return DD[dddddd & 3];
+ break;
+ case 1: return DDD[dddddd & 7];
+ case 2: return TTT[dddddd & 7];
+ case 3: return NNN[dddddd & 7];
+ case 4: return FFF[dddddd & 7];
+ case 7: return GGG[dddddd & 7];
+ }
+
+ return std::string("reserved");
+}
+
+std::string dsp56000_disassembler::ea(unsigned const MMMRRR, u16 const absolute) const
+{
+ unsigned const rrr = MMMRRR & 7;
+
+ switch (MMMRRR >> 3)
+ {
+ case 0: return util::string_format("(r%d)-n%d", rrr, rrr);
+ case 1: return util::string_format("(r%d)+n%d", rrr, rrr);
+ case 2: return util::string_format("(r%d)-", rrr);
+ case 3: return util::string_format("(r%d)+", rrr);
+ case 4: return util::string_format("(r%d)", rrr);
+ case 5: return util::string_format("(r%d+n%d)", rrr, rrr);
+ case 6: return util::string_format(">$%x", absolute);
+ case 7: return util::string_format("-(r%d)", rrr);
+ }
+
+ return std::string("invalid");
+}
diff --git a/src/devices/cpu/dsp56000/dsp56000d.h b/src/devices/cpu/dsp56000/dsp56000d.h
new file mode 100644
index 00000000000..30966746f49
--- /dev/null
+++ b/src/devices/cpu/dsp56000/dsp56000d.h
@@ -0,0 +1,25 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_CPU_DSP56000_DSP56000D_H
+#define MAME_CPU_DSP56000_DSP56000D_H
+
+#pragma once
+
+class dsp56000_disassembler : public util::disasm_interface
+{
+public:
+ dsp56000_disassembler() = default;
+ virtual ~dsp56000_disassembler() = default;
+
+ // disasm_interface overrides
+ virtual u32 opcode_alignment() const override { return 1; }
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const &params) override;
+
+private:
+ // helpers
+ std::string reg(unsigned const dddddd) const;
+ std::string ea(unsigned const MMMRRR, u16 const absolute = 0) const;
+};
+
+#endif // MAME_CPU_DSP56000_DSP56000D_H