summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2018-03-17 06:51:50 +1100
committer Vas Crabb <vas@vastheman.com>2018-03-17 06:51:50 +1100
commit5976a48035faf5663a985bd347967f4937b645bd (patch)
treed2a11fe604d5a156a4de0c56a5577fa7a21c0794
parent2d763608256f662d8915a9095a7cc844bf993dcc (diff)
dsp16: start adding recompiler boilerplate (nw)
-rw-r--r--scripts/src/cpu.lua6
-rw-r--r--src/devices/cpu/dsp16/dsp16.cpp2
-rw-r--r--src/devices/cpu/dsp16/dsp16.h3
-rw-r--r--src/devices/cpu/dsp16/dsp16fe.cpp859
-rw-r--r--src/devices/cpu/dsp16/dsp16fe.h108
5 files changed, 975 insertions, 3 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index ee4ebc3328f..57b61f048b1 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -13,7 +13,7 @@
-- Dynamic recompiler objects
--------------------------------------------------
-if (CPUS["E1"]~=null or CPUS["SH"]~=null or CPUS["MIPS"]~=null or CPUS["POWERPC"]~=null or CPUS["RSP"]~=null or CPUS["ARM7"]~=null or CPUS["ADSP21062"]~=null or CPUS["MB86235"]~=null) then
+if (CPUS["E1"]~=null or CPUS["SH"]~=null or CPUS["MIPS"]~=null or CPUS["POWERPC"]~=null or CPUS["RSP"]~=null or CPUS["ARM7"]~=null or CPUS["ADSP21062"]~=null or CPUS["MB86235"]~=null or CPUS["DSP16"]~=null) then
files {
MAME_DIR .. "src/devices/cpu/drcbec.cpp",
MAME_DIR .. "src/devices/cpu/drcbec.h",
@@ -261,6 +261,8 @@ if (CPUS["DSP16"]~=null) then
files {
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.cpp",
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.h",
+ MAME_DIR .. "src/devices/cpu/dsp16/dsp16fe.cpp",
+ MAME_DIR .. "src/devices/cpu/dsp16/dsp16fe.h",
}
end
@@ -1018,7 +1020,7 @@ if (CPUS["I86"]~=null) then
}
end
-if (CPUS["E1"]~=null or CPUS["SH"]~=null or CPUS["MIPS"]~=null or CPUS["POWERPC"]~=null or CPUS["RSP"]~=null or CPUS["ARM7"]~=null or CPUS["ADSP21062"]~=null or CPUS["MB86235"]~=null or CPUS["I86"]~=null or CPUS["I386"]~=null or _OPTIONS["with-tools"]) then
+if (CPUS["E1"]~=null or CPUS["SH"]~=null or CPUS["MIPS"]~=null or CPUS["POWERPC"]~=null or CPUS["RSP"]~=null or CPUS["ARM7"]~=null or CPUS["ADSP21062"]~=null or CPUS["MB86235"]~=null or CPUS["DSP16"]~=null or CPUS["I86"]~=null or CPUS["I386"]~=null or _OPTIONS["with-tools"]) then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/i386/i386dasm.cpp")
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/i386/i386dasm.h")
end
diff --git a/src/devices/cpu/dsp16/dsp16.cpp b/src/devices/cpu/dsp16/dsp16.cpp
index 27445c16ee1..36f1a2d5085 100644
--- a/src/devices/cpu/dsp16/dsp16.cpp
+++ b/src/devices/cpu/dsp16/dsp16.cpp
@@ -1043,8 +1043,8 @@ inline void dsp16_device_base::execute_one_rom()
m_st_pcbase);
set_iack(FLAGS_IACK_SET);
m_xaau_pc = 0x0002U;
- m_phase = phase::PURGE;
}
+ m_phase = phase::PURGE;
break;
case 0x1d: // F1 ; Z : y ; x = *pt++[i]
diff --git a/src/devices/cpu/dsp16/dsp16.h b/src/devices/cpu/dsp16/dsp16.h
index 6e90c9eff5f..ac58b0ef0e4 100644
--- a/src/devices/cpu/dsp16/dsp16.h
+++ b/src/devices/cpu/dsp16/dsp16.h
@@ -206,6 +206,9 @@ private:
friend sio_flags &operator&=(sio_flags &, sio_flags);
friend sio_flags &operator|=(sio_flags &, sio_flags);
+ // recompiler helpers
+ class frontend;
+
// internal address maps
void program_map(address_map &map);
diff --git a/src/devices/cpu/dsp16/dsp16fe.cpp b/src/devices/cpu/dsp16/dsp16fe.cpp
new file mode 100644
index 00000000000..113fc9d7035
--- /dev/null
+++ b/src/devices/cpu/dsp16/dsp16fe.cpp
@@ -0,0 +1,859 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ WE|AT&T DSP16 series emulator
+
+***************************************************************************/
+
+#include "emu.h"
+#include "dsp16fe.h"
+
+
+dsp16_device_base::frontend::frontend(dsp16_device_base &host, u32 window_start, u32 window_end, u32 max_sequence)
+ : drc_frontend(host, window_start, window_end, max_sequence)
+ , m_host(host)
+{
+}
+
+/***********************************************************************
+ drc_frontend implementation
+***********************************************************************/
+
+bool dsp16_device_base::frontend::describe(opcode_desc &desc, opcode_desc const *prev)
+{
+ // most instructions are one word long and run in one machine cycle
+ desc.length = 1U;
+ desc.cycles = 1U;
+
+ u16 const op(m_host.m_direct->read_word(desc.physpc));
+ switch (op >> 11)
+ {
+ case 0x00: // goto JA
+ case 0x01:
+ case 0x10: // call JA
+ case 0x11:
+ desc.cycles = 2U;
+ desc.targetpc = (desc.physpc & XAAU_I_EXT) | (op_ja(op) & XAAU_I_MASK);
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH;
+ if (BIT(op, 15))
+ flag_output_reg(desc, REG_BIT_XAAU_PR);
+ return true;
+
+ case 0x02: // R = M
+ case 0x03:
+ flag_output_reg(desc, REG_BIT_YAAU_R0 + (((op >> 9) & 0x0007U) ^ 0x0004U));
+ return true;
+
+ case 0x04: // F1 ; Y = a1[l]
+ case 0x1c: // F1 ; Y = a0[l]
+ desc.cycles = 2U;
+ flag_input_reg(desc, BIT(op, 14) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_AUC);
+ describe_f1(desc, op);
+ describe_y(desc, op, false, true);
+ return true;
+
+ case 0x05: // F1 ; Z : aT[l]
+ desc.cycles = 2U;
+ flag_input_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_PSW);
+ describe_f1(desc, op);
+ describe_z(desc, op);
+ return true;
+
+ case 0x06: // F1 ; Y
+ describe_f1(desc, op);
+ describe_y(desc, op, bool(m_host.machine().debug_flags & DEBUG_FLAG_ENABLED), false); // only read memory for watchpoints
+ return true;
+
+ case 0x07: // F1 ; aT[l] = Y
+ flag_output_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_PSW);
+ describe_f1(desc, op);
+ describe_y(desc, op, true, false);
+ return true;
+
+ case 0x08: // aT = R
+ desc.cycles = 2U;
+ if (op & 0x000fU) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ flag_output_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_PSW);
+ describe_r(desc, op, true, false);
+ return true;
+
+ case 0x09: // R = a0
+ case 0x0b: // R = a1
+ desc.cycles = 2U;
+ if (op & 0x000fU) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ flag_input_reg(desc, BIT(op, 12) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0, REG_BIT_DAU_AUC);
+ describe_r(desc, op, false, true);
+ return true;
+
+ case 0x0a: // R = N
+ desc.length = 2U;
+ desc.cycles = 2U;
+ if (op & 0x000fU) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ describe_r(desc, op, false, true);
+ return true;
+
+ case 0x0c: // Y = R
+ desc.cycles = 2U;
+ if (op & 0x0400U) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ describe_r(desc, op, true, false);
+ describe_y(desc, op, false, true);
+ return true;
+
+ case 0x0d: // Z : R
+ desc.cycles = 2U;
+ describe_r(desc, op, true, true);
+ describe_z(desc, op);
+ return true;
+
+ case 0x0e: // do K { instre1...instrNI } # redo K
+ if (op_ni(op))
+ return describe_do(desc, op);
+ else
+ return describe_redo(desc, op);
+
+ case 0x0f: // R = Y
+ desc.cycles = 2U;
+ if (op & 0x0400U) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ describe_r(desc, op, false, true);
+ describe_y(desc, op, true, false);
+ return true;
+
+ case 0x12: // ifc CON F2
+ flag_input_reg(desc, REG_BIT_DAU_C1);
+ flag_output_reg(desc, REG_BIT_DAU_C1, REG_BIT_DAU_C2);
+ describe_con(desc, op, false);
+ describe_f2(desc, op);
+ return true;
+
+ case 0x13: // if CON F2
+ describe_con(desc, op, true);
+ describe_f2(desc, op);
+ return true;
+
+ case 0x14: // F1 ; Y = y[l]
+ desc.cycles = 2U;
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_y(desc, op, false, true);
+ return true;
+
+ case 0x15: // F1 ; Z : y[l]
+ desc.cycles = 2U;
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_z(desc, op);
+ return true;
+
+ case 0x16: // F1 ; x = Y
+ flag_output_reg(desc, REG_BIT_DAU_X);
+ describe_f1(desc, op);
+ describe_y(desc, op, true, false);
+ return true;
+
+ case 0x17: // F1 ; y[l] = Y
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_y(desc, op, true, false);
+ return true;
+
+ case 0x18: // goto B
+ return describe_goto_b(desc, op);
+
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i]
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
+ desc.cycles = 2U;
+ if (op & 0x000fU)
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ flag_input_reg(desc, BIT(op, 12) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_x(desc, op);
+ return true;
+
+ case 0x1a: // if CON # icall
+ if (op & 0x03e0U) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ if (BIT(op, 10))
+ return describe_icall(desc, op);
+ else
+ return describe_if_con(desc, op);
+
+ case 0x1d: // F1 ; Z : y ; x = *pt++[i]
+ desc.cycles = 2U;
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_x(desc, op);
+ describe_z(desc, op);
+ return true;
+
+ case 0x1e: // Reserved
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ return true;
+
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ desc.cycles = 2U;
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_x(desc, op);
+ describe_y(desc, op, true, false);
+ return true;
+ };
+
+ return false;
+}
+
+/***********************************************************************
+ program fetch helpers
+***********************************************************************/
+
+u16 dsp16_device_base::frontend::read_op(opcode_desc const &desc, u16 offset) const
+{
+ return m_host.m_direct->read_word((desc.physpc & XAAU_I_EXT) | ((desc.physpc + offset) & XAAU_I_MASK));
+}
+
+/***********************************************************************
+ non-trivial instruction helpers
+***********************************************************************/
+
+bool dsp16_device_base::frontend::describe_goto_b(opcode_desc &desc, u16 op)
+{
+ desc.cycles = 2U;
+ if (op & 0x00ffU)
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH;
+ switch (op_b(op))
+ {
+ case 0x0: // return
+ flag_input_reg(desc, REG_BIT_XAAU_PR);
+ break;
+ case 0x1: // ireturn
+ desc.flags |= OPFLAG_CAN_CHANGE_MODES; // FIXME: is this flag useful for a switch in/out of interrupt service mode?
+ flag_input_reg(desc, REG_BIT_XAAU_PI);
+ break;
+ case 0x2: // goto pt
+ flag_input_reg(desc, REG_BIT_XAAU_PT);
+ break;
+ case 0x3: // call pt
+ flag_input_reg(desc, REG_BIT_XAAU_PT);
+ flag_output_reg(desc, REG_BIT_XAAU_PR);
+ break;
+ case 0x4: // Reserved
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ break;
+ }
+ return true;
+}
+
+bool dsp16_device_base::frontend::describe_if_con(opcode_desc &desc, u16 op)
+{
+ // look ahead and see if the next instruction can be predicated
+ u16 const next(read_imm(desc));
+ switch (next >> 11)
+ {
+ case 0x00: // goto JA
+ case 0x01:
+ case 0x10: // call JA
+ case 0x11:
+ desc.cycles = 3U;
+ desc.length = 2U;
+ switch (op_con(op))
+ {
+ case 0xe: // true
+ desc.targetpc = (desc.physpc & XAAU_I_EXT) | (op_ja(next) & XAAU_I_MASK);
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH;
+ if (BIT(next, 15))
+ flag_output_reg(desc, REG_BIT_XAAU_PR);
+ break;
+ case 0xf: // false
+ break;
+ default:
+ desc.targetpc = (desc.physpc & XAAU_I_EXT) | (op_ja(next) & XAAU_I_MASK);
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ if (BIT(next, 15))
+ flag_output_reg(desc, REG_BIT_XAAU_PR);
+ }
+ break;
+
+ case 0x18: // goto B
+ desc.cycles = 3U;
+ desc.length = 2U;
+ if (op_b(next) == 0x1)
+ switch (op_b(next))
+ {
+ case 0x0: // return
+ case 0x2: // goto pt
+ case 0x3: // call pt
+ break;
+ case 0x1: // can't predicate ireturn?
+ case 0x4: // Reserved
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ break;
+ }
+ if (op_b(next) == 0x1) // can't predicate ireturn?
+ {
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_CAN_CHANGE_MODES; // FIXME: confirm appropriate flags
+ flag_input_reg(desc, REG_BIT_XAAU_PI);
+ }
+ else
+ {
+ switch (op_con(op))
+ {
+ case 0xe: // true
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH;
+ switch (op_b(next))
+ {
+ case 0x0: // return
+ flag_input_reg(desc, REG_BIT_XAAU_PR);
+ break;
+ case 0x2: // goto pt
+ flag_input_reg(desc, REG_BIT_XAAU_PT);
+ break;
+ case 0x3: // call pt
+ flag_input_reg(desc, REG_BIT_XAAU_PT);
+ flag_output_reg(desc, REG_BIT_XAAU_PR);
+ break;
+ }
+ break;
+ case 0xf: // false
+ break;
+ default:
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ switch (op_b(next))
+ {
+ case 0x0: // return
+ flag_input_reg(desc, REG_BIT_XAAU_PR);
+ break;
+ case 0x2: // goto pt
+ flag_input_reg(desc, REG_BIT_XAAU_PT);
+ break;
+ case 0x3: // call pt
+ flag_input_reg(desc, REG_BIT_XAAU_PT);
+ flag_output_reg(desc, REG_BIT_XAAU_PR);
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ desc.flags |= OPFLAG_INVALID_OPCODE; // can't predicate things that aren't branches?
+ }
+ describe_con(desc, op, true);
+ return true;
+}
+
+bool dsp16_device_base::frontend::describe_icall(opcode_desc &desc, u16 op)
+{
+ desc.cycles = 3U;
+ if (0x000eU != op_con(op)) // CON must be true for icall?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ switch (op_con(op))
+ {
+ case 0xe: // true
+ desc.targetpc = 0x0002U;
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_CAN_CHANGE_MODES; // FIXME: confirm appropriate flags
+ break;
+ case 0xf: // false
+ break;
+ default:
+ desc.targetpc = 0x0002U;
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH | OPFLAG_CAN_CHANGE_MODES; // FIXME: confirm appropriate flags
+ }
+ describe_con(desc, op, true);
+ return true;
+}
+
+bool dsp16_device_base::frontend::describe_do(opcode_desc &desc, u16 op)
+{
+ u16 const ni(op_ni(op)), k(op_k(op));
+ if (2U > k) // p3-25: "The iteration count can be between 2 and 127, inclusive"
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ desc.length = ni + 1;
+ u32 cycles(0U), romcycles(0U), cachecycles(0U);
+ for (u16 i = 0; i < ni; ++i)
+ {
+ u16 const next(read_op(desc, i + 1));
+ switch (next >> 11)
+ {
+ case 0x02: // R = M
+ case 0x03:
+ romcycles = cachecycles = 1U;
+ flag_output_reg(desc, REG_BIT_YAAU_R0 + (((next >> 9) & 0x0007U) ^ 0x0004U));
+ break;
+
+ case 0x04: // F1 ; Y = a1[l]
+ case 0x1c: // F1 ; Y = a0[l]
+ romcycles = cachecycles = 2U;
+ flag_input_reg(desc, BIT(op, 14) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_AUC);
+ describe_f1(desc, op);
+ describe_y(desc, op, false, true);
+ break;
+
+ case 0x05: // F1 ; Z : aT[l]
+ romcycles = cachecycles = 2U;
+ flag_input_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_PSW);
+ describe_f1(desc, op);
+ describe_z(desc, op);
+ break;
+
+ case 0x06: // F1 ; Y
+ romcycles = cachecycles = 1U;
+ describe_f1(desc, op);
+ describe_y(desc, op, bool(m_host.machine().debug_flags & DEBUG_FLAG_ENABLED), false); // only read memory for watchpoints
+ break;
+
+ case 0x07: // F1 ; aT[l] = Y
+ romcycles = cachecycles = 1U;
+ flag_output_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_PSW);
+ describe_f1(desc, op);
+ describe_y(desc, op, true, false);
+ break;
+
+ case 0x08: // aT = R
+ romcycles = cachecycles = 2U;
+ if (op & 0x000fU) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ flag_output_reg(desc, op_d(op) ? REG_BIT_DAU_A0 : REG_BIT_DAU_A1, REG_BIT_DAU_PSW);
+ describe_r(desc, op, true, false);
+ break;
+
+ case 0x09: // R = a0
+ case 0x0b: // R = a1
+ romcycles = cachecycles = 2U;
+ if (op & 0x000fU) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ flag_input_reg(desc, BIT(op, 12) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0, REG_BIT_DAU_AUC);
+ describe_r(desc, op, false, true);
+ break;
+
+ case 0x0c: // Y = R
+ romcycles = cachecycles = 2U;
+ if (op & 0x0400U) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ describe_r(desc, op, true, false);
+ describe_y(desc, op, false, true);
+ break;
+
+ case 0x0d: // Z : R
+ romcycles = cachecycles = 2U;
+ describe_r(desc, op, true, true);
+ describe_z(desc, op);
+ break;
+
+ case 0x0f: // R = Y
+ romcycles = cachecycles = 2U;
+ if (op & 0x0400U) // reserved field?
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ describe_r(desc, op, false, true);
+ describe_y(desc, op, true, false);
+ break;
+
+ case 0x12: // ifc CON F2
+ romcycles = cachecycles = 1U;
+ flag_input_reg(desc, REG_BIT_DAU_C1);
+ flag_output_reg(desc, REG_BIT_DAU_C1, REG_BIT_DAU_C2);
+ describe_con(desc, op, false);
+ describe_f2(desc, op);
+ break;
+
+ case 0x13: // if CON F2
+ romcycles = cachecycles = 1U;
+ describe_con(desc, op, true);
+ describe_f2(desc, op);
+ break;
+
+ case 0x14: // F1 ; Y = y[l]
+ romcycles = cachecycles = 2U;
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_y(desc, op, false, true);
+ break;
+
+ case 0x15: // F1 ; Z : y[l]
+ romcycles = cachecycles = 2U;
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_z(desc, op);
+ break;
+
+ case 0x16: // F1 ; x = Y
+ romcycles = cachecycles = 1U;
+ flag_output_reg(desc, REG_BIT_DAU_X);
+ describe_f1(desc, op);
+ describe_y(desc, op, true, false);
+ break;
+
+ case 0x17: // F1 ; y[l] = Y
+ romcycles = cachecycles = 1U;
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_y(desc, op, true, false);
+ break;
+
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i]
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
+ romcycles = 2U;
+ cachecycles = 1U;
+ if (op & 0x000fU)
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ flag_input_reg(desc, BIT(op, 12) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_x(desc, op);
+ break;
+
+ case 0x1d: // F1 ; Z : y ; x = *pt++[i]
+ romcycles = cachecycles = 2U;
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_x(desc, op);
+ describe_z(desc, op);
+ break;
+
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ romcycles = 2U;
+ cachecycles = 1U;
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ describe_f1(desc, op);
+ describe_x(desc, op);
+ describe_y(desc, op, true, false);
+ break;
+
+ case 0x00: // goto JA
+ case 0x01:
+ case 0x10: // call JA
+ case 0x11:
+ case 0x0a: // R = N
+ case 0x0e: // do K { instre1...instrNI } # redo K
+ case 0x18: // goto B
+ case 0x1a: // if CON # icall
+ case 0x1e: // Reserved
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ m_cache_valid = false;
+ return false; // not going to get into what happens if you cache ineligible instructions
+ }
+ desc.cycles += romcycles;
+ cycles += cachecycles;
+ }
+ m_cache_cycles = cycles;
+ m_cache_last_cycles = cycles + (romcycles - cachecycles);
+ m_cache_flags = desc.flags & (OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY);
+ std::copy_n(desc.regin, ARRAY_LENGTH(desc.regin), m_cache_regin);
+ std::copy_n(desc.regout, ARRAY_LENGTH(desc.regout), m_cache_regout);
+ std::copy_n(desc.regreq, ARRAY_LENGTH(desc.regreq), m_cache_regreq);
+ m_cache_valid = true;
+ desc.cycles += (2U - romcycles) + ((k - 1) * cycles) + (romcycles - cachecycles);
+ return true;
+}
+
+bool dsp16_device_base::frontend::describe_redo(opcode_desc &desc, u16 op)
+{
+ desc.cycles = 2U;
+ u16 const k(op_k(op));
+ if (2U > k) // p3-25: "The iteration count can be between 2 and 127, inclusive"
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+
+ // assume that the block follwoing the last do K { ... } we examined is still cached - we can check properly when we actually run
+ if (!m_cache_valid)
+ {
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ return false;
+ }
+ else
+ {
+ desc.cycles += ((k - 1) * m_cache_cycles) + m_cache_last_cycles;
+ desc.flags |= m_cache_flags;
+ std::copy_n(m_cache_regin, ARRAY_LENGTH(desc.regin), desc.regin);
+ std::copy_n(m_cache_regout, ARRAY_LENGTH(desc.regout), desc.regout);
+ std::copy_n(m_cache_regreq, ARRAY_LENGTH(desc.regreq), desc.regreq);
+ return true;
+ }
+}
+
+/***********************************************************************
+ sub-operation helpers
+***********************************************************************/
+
+void dsp16_device_base::frontend::describe_r(opcode_desc &desc, u16 op, bool read, bool write)
+{
+ u8 const r(op_r(op));
+ switch (r)
+ {
+ case 0x00: // r0 (u)
+ case 0x01: // r1 (u)
+ case 0x02: // r2 (u)
+ case 0x03: // r3 (u)
+ case 0x04: // j (s)
+ case 0x05: // k (s)
+ case 0x06: // rb (u)
+ case 0x07: // re (u)
+ case 0x08: // pt
+ case 0x09: // pr
+ case 0x0b: // i (s)
+ case 0x10: // x
+ case 0x11: // y
+ case 0x13: // auc (u)
+ case 0x15: // c0 (s)
+ case 0x16: // c1 (s)
+ case 0x17: // c2 (s)
+ if (read)
+ flag_input_reg(desc, r);
+ if (write)
+ flag_output_reg(desc, r);
+ break;
+ case 0x0a: // pi
+ // FIXME: mode-sensitive and resets PRNG
+ if (read)
+ flag_input_reg(desc, REG_BIT_XAAU_PI);
+ if (write)
+ flag_output_reg(desc, REG_BIT_XAAU_PI);
+ break;
+ case 0x12: // yl
+ if (read)
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ if (write)
+ flag_output_reg(desc, REG_BIT_DAU_Y);
+ break;
+ case 0x14: // psw
+ if (read)
+ flag_input_reg(desc, REG_BIT_DAU_PSW);
+ if (write)
+ flag_output_reg(desc, REG_BIT_DAU_A0, REG_BIT_DAU_A1, REG_BIT_DAU_PSW);
+ break;
+ case 0x18: // sioc
+ case 0x19: // srta
+ case 0x1b: // tdms
+ if (read)
+ flag_input_reg(desc, r);
+ if (write)
+ flag_required_output_reg(desc, r);
+ break;
+ case 0x1a: // sdx
+ if (write)
+ flag_required_output_reg(desc, r);
+ break;
+ case 0x1c: // pioc
+ case 0x1d: // pdx0
+ case 0x1e: // pdx1
+ break;
+ default:
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ }
+}
+
+void dsp16_device_base::frontend::describe_con(opcode_desc &desc, u16 op, bool inc)
+{
+ u16 const con(op_con(op));
+ switch (con >> 1)
+ {
+ case 0x0: // mi/pl
+ case 0x1: // eq/ne
+ case 0x2: // lvs/lvc
+ case 0x3: // mvs/mvc
+ case 0x8: // gt/le
+ flag_input_reg(desc, REG_BIT_DAU_PSW);
+ break;
+ case 0x4: // heads/tails
+ throw emu_fatalerror("DSP16: unimplemented CON value %02X (PC = %04X)\n", con, desc.physpc);
+ case 0x5: // c0ge/c0lt
+ case 0x6: // c1ge/c1lt
+ {
+
+ u8 const c(REG_BIT_DAU_C0 + (con >> 1) - 0x05);
+ flag_input_reg(desc, c);
+ if (inc)
+ flag_output_reg(desc, c);
+ }
+ break;
+ case 0x7: // true/false
+ break;
+ default:
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ }
+}
+
+void dsp16_device_base::frontend::describe_f1(opcode_desc &desc, u16 op)
+{
+ u32 const s(op_s(op) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0);
+ u32 const d(op_d(op) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0);
+ switch (op_f1(op))
+ {
+ case 0x0: // aD = p ; p = x*y
+ flag_input_reg(desc, REG_BIT_DAU_X, REG_BIT_DAU_Y, REG_BIT_DAU_P, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, d, REG_BIT_DAU_P, REG_BIT_DAU_PSW);
+ break;
+ case 0x1: // aD = aS + p ; p = x*y
+ flag_input_reg(desc, s, REG_BIT_DAU_X, REG_BIT_DAU_Y, REG_BIT_DAU_P, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, d, REG_BIT_DAU_P, REG_BIT_DAU_PSW);
+ break;
+ case 0x2: // p = x*y
+ flag_input_reg(desc, REG_BIT_DAU_X, REG_BIT_DAU_Y);
+ flag_output_reg(desc, REG_BIT_DAU_P);
+ break;
+ case 0x3: // aD = aS - p ; p = x*y
+ flag_input_reg(desc, s, REG_BIT_DAU_X, REG_BIT_DAU_Y, REG_BIT_DAU_P, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, d, REG_BIT_DAU_P, REG_BIT_DAU_PSW);
+ break;
+ case 0x4: // aD = p
+ flag_input_reg(desc, REG_BIT_DAU_P, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0x5: // aD = aS + p
+ flag_input_reg(desc, s, REG_BIT_DAU_P, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0x6: // NOP
+ break;
+ case 0x7: // aD = aS - p
+ flag_input_reg(desc, s, REG_BIT_DAU_P, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0x8: // aD = aS | y
+ flag_input_reg(desc, s, REG_BIT_DAU_Y);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0x9: // aD = aS ^ y
+ flag_input_reg(desc, s, REG_BIT_DAU_Y);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0xa: // aS & y
+ flag_input_reg(desc, s, REG_BIT_DAU_Y);
+ flag_output_reg(desc, REG_BIT_DAU_PSW);
+ break;
+ case 0xb: // aS - y
+ flag_input_reg(desc, s, REG_BIT_DAU_Y);
+ flag_output_reg(desc, REG_BIT_DAU_PSW);
+ break;
+ case 0xc: // aD = y
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0xd: // aD = aS + y
+ flag_input_reg(desc, s, REG_BIT_DAU_Y);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0xe: // aD = aS & y
+ flag_input_reg(desc, s, REG_BIT_DAU_Y);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0xf: // aD = aS - y
+ flag_input_reg(desc, s, REG_BIT_DAU_Y);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ }
+}
+
+void dsp16_device_base::frontend::describe_f2(opcode_desc &desc, u16 op)
+{
+ u32 const s(op_s(op) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0);
+ u32 const d(op_d(op) ? REG_BIT_DAU_A1 : REG_BIT_DAU_A0);
+ switch (op_f2(op))
+ {
+ case 0x0: // aD = aS >> 1
+ case 0x1: // aD = aS << 1
+ case 0x2: // aD = aS >> 4
+ case 0x3: // aD = aS << 4
+ case 0x4: // aD = aS >> 8
+ case 0x5: // aD = aS << 8
+ case 0x6: // aD = aS >> 16
+ case 0x7: // aD = aS << 16
+ case 0x9: // aDh = aSh + 1
+ case 0xb: // aD = rnd(aS)
+ case 0xd: // aD = aS + 1
+ case 0xe: // aD = aS
+ case 0xf: // aD = -aS
+ flag_input_reg(desc, s);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0x8: // aD = p
+ flag_input_reg(desc, REG_BIT_DAU_P, REG_BIT_DAU_AUC);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ case 0xa: // Reserved
+ desc.flags |= OPFLAG_INVALID_OPCODE;
+ break;
+ case 0xc: // aD = y
+ flag_input_reg(desc, REG_BIT_DAU_Y);
+ flag_output_reg(desc, d, REG_BIT_DAU_PSW);
+ break;
+ }
+}
+
+void dsp16_device_base::frontend::describe_x(opcode_desc &desc, u16 op)
+{
+ desc.flags |= OPFLAG_READS_MEMORY; // TODO: is reading ROM the same as memory for dependency purposes?
+ flag_input_reg(desc, REG_BIT_XAAU_PT);
+ flag_output_reg(desc, REG_BIT_XAAU_PT, REG_BIT_DAU_X);
+ if (op_x(op))
+ flag_input_reg(desc, REG_BIT_XAAU_I);
+}
+
+void dsp16_device_base::frontend::describe_y(opcode_desc &desc, u16 op, bool read, bool write)
+{
+ u32 const r(REG_BIT_YAAU_R0 + ((op >> 2) && 0x0003U));
+ if (read)
+ desc.flags |= OPFLAG_READS_MEMORY;
+ if (write)
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ switch (op & 0x0003U)
+ {
+ case 0x0: // *rN
+ if (read || write)
+ flag_input_reg(desc, r);
+ break;
+ case 0x1: // *rN++
+ flag_input_reg(desc, r, REG_BIT_YAAU_RB, REG_BIT_YAAU_RE);
+ flag_output_reg(desc, r);
+ break;
+ case 0x2: // *rN--
+ flag_input_reg(desc, r);
+ flag_output_reg(desc, r);
+ break;
+ case 0x3: // *rN++j
+ flag_input_reg(desc, r, REG_BIT_YAAU_J);
+ flag_output_reg(desc, r);
+ break;
+ }
+}
+
+void dsp16_device_base::frontend::describe_z(opcode_desc &desc, u16 op)
+{
+ u32 const r(REG_BIT_YAAU_R0 + ((op >> 2) && 0x0003U));
+ desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY;
+ flag_output_reg(desc, r);
+ switch (op & 0x0003U)
+ {
+ case 0x0: // *rNzp
+ case 0x1: // *rNpz
+ flag_input_reg(desc, r, REG_BIT_YAAU_RB, REG_BIT_YAAU_RE);
+ break;
+ case 0x2: // *rNm2
+ flag_input_reg(desc, r);
+ break;
+ case 0x3: // *rNjk
+ flag_input_reg(desc, r, REG_BIT_YAAU_J, REG_BIT_YAAU_K);
+ break;
+ }
+}
diff --git a/src/devices/cpu/dsp16/dsp16fe.h b/src/devices/cpu/dsp16/dsp16fe.h
new file mode 100644
index 00000000000..96dcbbe51de
--- /dev/null
+++ b/src/devices/cpu/dsp16/dsp16fe.h
@@ -0,0 +1,108 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ WE|AT&T DSP16 series emulator
+
+***************************************************************************/
+#ifndef MAME_CPU_DSP16_DSP16FE_H
+#define MAME_CPU_DSP16_DSP16FE_H
+
+#pragma once
+
+#include "dsp16.h"
+
+#include "cpu/drcfe.h"
+
+
+class dsp16_device_base::frontend : public drc_frontend
+{
+public:
+ enum : u8
+ {
+ // in the same order as the R field for convenience
+ // only include registers useful for dependency analysis here
+
+ REG_BIT_YAAU_R0 = 0x00U,
+ REG_BIT_YAAU_R1,
+ REG_BIT_YAAU_R2,
+ REG_BIT_YAAU_R3,
+ REG_BIT_YAAU_J,
+ REG_BIT_YAAU_K,
+ REG_BIT_YAAU_RB,
+ REG_BIT_YAAU_RE,
+
+ REG_BIT_XAAU_PT = 0x08U,
+ REG_BIT_XAAU_PR,
+ REG_BIT_XAAU_PI, // handled specially
+ REG_BIT_XAAU_I,
+
+ REG_BIT_DAU_X = 0x10U,
+ REG_BIT_DAU_Y,
+ // yl isn't an independent register
+ REG_BIT_DAU_AUC = 0x13U,
+ REG_BIT_DAU_PSW,
+ REG_BIT_DAU_C0,
+ REG_BIT_DAU_C1,
+ REG_BIT_DAU_C2,
+
+ REG_BIT_SIO_SIOC = 0x18U,
+ REG_BIT_SIO_SRTA,
+ REG_BIT_SIO_SDX,
+ REG_BIT_SIO_TDMS,
+
+ // registers not accessible via the R field in gaps
+ REG_BIT_DAU_P = 0x0dU,
+ REG_BIT_DAU_A0,
+ REG_BIT_DAU_A1
+ };
+
+ frontend(dsp16_device_base &host, u32 window_start, u32 window_end, u32 max_sequence);
+
+protected:
+ // drc_frontend implementation
+ virtual bool describe(opcode_desc &desc, opcode_desc const *prev) override;
+
+private:
+ // program fetch helpers
+ u16 read_op(opcode_desc const &desc, u16 offset) const;
+ u16 read_op(opcode_desc const &desc) const { return read_op(desc, 0U); }
+ u16 read_imm(opcode_desc const &desc) const { return read_op(desc, 1U); }
+
+ // non-trivial instruction helpers
+ bool describe_goto_b(opcode_desc &desc, u16 op);
+ bool describe_if_con(opcode_desc &desc, u16 op);
+ bool describe_icall(opcode_desc &desc, u16 op);
+ bool describe_do(opcode_desc &desc, u16 op);
+ bool describe_redo(opcode_desc &desc, u16 op);
+
+ // sub-operation helpers
+ static void describe_r(opcode_desc &desc, u16 op, bool read, bool write);
+ static void describe_con(opcode_desc &desc, u16 op, bool inc);
+ static void describe_f1(opcode_desc &desc, u16 op);
+ static void describe_f2(opcode_desc &desc, u16 op);
+ static void describe_x(opcode_desc &desc, u16 op);
+ static void describe_y(opcode_desc &desc, u16 op, bool read, bool write);
+ static void describe_z(opcode_desc &desc, u16 op);
+
+ // field access helpers
+ static void flag_reg(u32 (&flags)[4]) { }
+ template <typename... T> static void flag_reg(u32 (&flags)[4], u8 reg0, T... regn)
+ {
+ flags[reg0 >> 5] |= (u32(1) << (reg0 & (u32(32) - 1)));
+ flag_reg(flags, regn...);
+ }
+ template <typename... T> static void flag_input_reg(opcode_desc &desc, T... reg) { flag_reg(desc.regin, reg...); }
+ template <typename... T> static void flag_output_reg(opcode_desc &desc, T... reg) { flag_reg(desc.regout, reg...); }
+ template <typename... T> static void flag_required_output_reg(opcode_desc &desc, T... reg) { flag_reg(desc.regreq, reg...); }
+
+ // need access to host device for program fetch
+ dsp16_device_base const &m_host;
+
+ // for making sweeping assumptions
+ u32 m_cache_cycles = 0U, m_cache_last_cycles = 0U, m_cache_flags = 0U;
+ decltype(opcode_desc::regin) m_cache_regin, m_cache_regout, m_cache_regreq;
+ bool m_cache_valid = false;
+};
+
+#endif // MAME_CPU_DSP16_DSP16FE_H