summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2018-03-15 19:02:43 +1100
committer Vas Crabb <vas@vastheman.com>2018-03-15 19:02:43 +1100
commit0bf88bda8f80a824a935c2b7adb7b72e54f9938a (patch)
tree0f0c3aa3e01c4c809cba091133f1fd18ae85bf40 /src
parent25652d645587c96a906a6f0b809c0c80a995aab5 (diff)
Cycle-accurate DSP16 core (disabled in QSound for performance reasons)
Diffstat (limited to 'src')
-rw-r--r--src/devices/cpu/dsp16/dsp16.cpp2334
-rw-r--r--src/devices/cpu/dsp16/dsp16.h567
-rw-r--r--src/devices/cpu/dsp16/dsp16ops.hxx937
-rw-r--r--src/devices/sound/qsound.cpp50
-rw-r--r--src/devices/sound/qsound.h36
-rw-r--r--src/emu/validity.cpp2
-rw-r--r--src/mame/drivers/cps1.cpp2
-rw-r--r--src/mame/drivers/cps2.cpp2
-rw-r--r--src/mame/drivers/vgmplay.cpp2
-rw-r--r--src/mame/drivers/zn.cpp6
10 files changed, 2465 insertions, 1473 deletions
diff --git a/src/devices/cpu/dsp16/dsp16.cpp b/src/devices/cpu/dsp16/dsp16.cpp
index 33c25a32dc6..ba5737087b0 100644
--- a/src/devices/cpu/dsp16/dsp16.cpp
+++ b/src/devices/cpu/dsp16/dsp16.cpp
@@ -1,430 +1,2108 @@
// license:BSD-3-Clause
-// copyright-holders:Andrew Gardner
+// copyright-holders:Vas Crabb
/***************************************************************************
- dsp16.h
+ WE|AT&T DSP16 series emulator
- WE|AT&T DSP16 series emulator.
+ There are three basic functional units:
+ * XAAU: ROM Address Arithmetic Unit
+ - Four 16-bit address registers (pc, pt, pr, pi)
+ - One 12-bit increment register (i)
+ - One 12-bit adder
+ * YAAU: RAM Address Arithmetic Unit
+ - Four 9-bit or 16-bit pointer registers (r0, r1, r2, r3)
+ - Two 9-bit or 16-bit increment registers (j, k)
+ - Two 9-bit or 16-bit array boundary registers (rb, re)
+ - One 9-bit or 16-bit adder
+ * DAU: Data Arithmetic Unit
+ - One 16-bit multiplier register (x)
+ - One 32-bit source register (y)
+ - One 32-bit product register (p)
+ - Two 36-bit accumulators (a0, a1)
+ - Three 8-bit counter registers (c0, c1, c2)
+ - One 7-bit control register (auc)
+ - One 16-bit status register (psw)
+ - One 16*16->32 multiplier
+ - One 36-bit ALU
+ - One 36->16 extract/saturate unit
+
+ The instruction set allows for explicit parallelism. It's possible
+ to issue a multiply, and ALU operation, a RAM/ROM transfer, and a
+ pointer postmodification in a single instruction.
+
+ There's a 15-word "cache" that the DSP can execute from without the
+ cost of instruction fetches. There's an instruction to cache the
+ next N instructions and repeat them M times, and in instruction to
+ execute the currently cached instructions M times. Interrupts are
+ not serviced while executing from cache, and not all instructions
+ can be cached.
+
+ One ROM load and one RAM load/store can be issued per machine cycle.
+ Normally the DSP will overlap fetch/decode for the next instruction
+ with execution of the current instruction. However, when executing
+ from cache, the DSP doesn't need to fetch instructions from ROM so
+ it can overlap a data fetch for the next instruction with execution
+ of the current instruction. A RAM store can only occur in the
+ second machine cycle of an instruction.
+
+ When loading the cache, all but the last instruction loaded into the
+ cache run with with normal timings. The last instruction always
+ executes in two cycles. The second cycle is necessary to ensure the
+ DSP has an opportunity to overlap a data fetch for the first cached
+ instruction if necessary. On the final iteration, the last cached
+ instruction runs with normal timings, allowing the DSP to overlap
+ the fetch for the next instruction to be executed from ROM.
+
+ There's a buffered full duplex synchronous serial transceiver, and
+ a strobed parallel port. Both have have interrupt capability and
+ configurable timing.
+
+ The parallel port consists of sixteen bidirectional data lines
+ (PDB00-PDB15), a single peripheral select line (PSEL), a single
+ bidirectional input strobe line (PIDS), and a single bidirectional
+ output strobe line (PODS). In active mode, reading the port yields
+ the current value in the input register and initiates a read.
+
+ TODO:
+ * Remaining instructions
+ * PSW overflow bits
+ * Clarify rounding behaviour (F2 1011)
+ * Random condition
+ * Clarify serial behaviour
+ * Serial input
+ * More serial I/O signals
+ * Parallel I/O S/C mode
+ * More complete low-level parallel I/O hooks
***************************************************************************/
#include "emu.h"
-#include "debugger.h"
#include "dsp16.h"
#include "dsp16dis.h"
-//
-// TODO:
-// * Store the cache in 15 unique memory locations as it is on-chip.
-// * Modify cycle counts when running from within the cache
-// * A write to PI resets the pseudoramdom sequence generator) (page 2-4)
-// * Handle virtual shift addressing using RB & RE (when RE is enabled) (page 2-6)
-// * The ALU sign-extends 32-bit operands from y or p to 36 bits and produces a 36-bit output
-// * Interrupt lines (page 2-15)
-//
-
-//**************************************************************************
-// DEVICE INTERFACE
-//**************************************************************************
-
-// device type definition
+#include "debugger.h"
+
+#include <functional>
+#include <limits>
+
+#define LOG_GENERAL (1U << 0)
+#define LOG_INT (1U << 1)
+#define LOG_SIO (1U << 2)
+#define LOG_PIO (1U << 3)
+
+//#define VERBOSE (LOG_GENERAL | LOG_INT | LOG_SIO | LOG_PIO)
+//#define LOG_OUTPUT_STREAM std::cout
+#include "logmacro.h"
+
+#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__)
+#define LOGSIO(...) LOGMASKED(LOG_SIO, __VA_ARGS__)
+#define LOGPIO(...) LOGMASKED(LOG_PIO, __VA_ARGS__)
+
+
+/***************************************************************************
+ DEVICE TYPE DEFINITIONS
+***************************************************************************/
+
DEFINE_DEVICE_TYPE(DSP16, dsp16_device, "dsp16", "DSP16")
+DEFINE_DEVICE_TYPE(DSP16A, dsp16a_device, "dsp16a", "DSP16A")
+
+
+/***************************************************************************
+ DSP16 SERIES BASE IMPLEMENTATION
+***************************************************************************/
+
+ALLOW_SAVE_TYPE(dsp16_device_base::cache);
+ALLOW_SAVE_TYPE(dsp16_device_base::phase);
+ALLOW_SAVE_TYPE(dsp16_device_base::flags);
+ALLOW_SAVE_TYPE(dsp16_device_base::sio_flags);
+
+WRITE_LINE_MEMBER(dsp16_device_base::exm_w)
+{
+ if (bool(state) != bool(m_exm_in))
+ {
+ m_exm_in = state ? 1U : 0U;
+ if (started())
+ external_memory_enable(*m_spaces[AS_PROGRAM], !m_exm_in);
+ }
+}
+
+/***********************************************************************
+ high-level passive parallel I/O handlers
+***********************************************************************/
+
+READ16_MEMBER(dsp16_device_base::pio_r)
+{
+ if (!pio_pods_active())
+ {
+ LOGPIO("DSP16: PIO host read PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, m_pio_pdx_out, m_st_pcbase);
+ if (!pio_pods_status())
+ LOGINT("DSP16: set PODS flag (PC = %04X)\n", m_st_pcbase);
+ m_pio_pioc |= u16(1) << 1;
+ return m_pio_pdx_out;
+ }
+ else
+ {
+ logerror("DSP16: warning: PIO host read in active mode - returning line status (PC = %04X)\n", m_st_pcbase);
+ // TODO: improve this when low-level interface is more complete
+ return !m_pods_out ? m_pio_pdx_out : 0xffffU;
+ }
+}
+
+WRITE16_MEMBER(dsp16_device_base::pio_w)
+{
+ if (!pio_pids_active())
+ {
+ LOGPIO("DSP16: PIO host write PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, data, m_st_pcbase);
+ if (!pio_pids_status())
+ LOGINT("DSP16: set PIDS flag (PC = %04X)\n", m_st_pcbase);
+ m_pio_pioc |= u16(1) << 2;
+ m_pio_pdx_in = data;
+ }
+ else
+ {
+ logerror("DSP16: warning: ignoring PIO host write in active mode (PC = %04X)\n", m_st_pcbase);
+ }
+}
+
+/***********************************************************************
+ construction/destruction
+***********************************************************************/
+
+dsp16_device_base::dsp16_device_base(
+ machine_config const &mconfig,
+ device_type type,
+ char const *tag,
+ device_t *owner,
+ u32 clock,
+ u8 yaau_bits,
+ address_map_constructor &&data_map)
+ : cpu_device(mconfig, type, tag, owner, clock)
+ , m_iack_cb(*this)
+ , m_ick_cb(*this), m_ild_cb(*this)
+ , m_do_cb(*this), m_ock_cb(*this), m_old_cb(*this), m_ose_cb(*this)
+ , m_pio_r_cb(*this), m_pio_w_cb(*this), m_pdb_w_cb(*this), m_psel_cb(*this), m_pids_cb(*this), m_pods_cb(*this)
+ , m_space_config{
+ { "rom", ENDIANNESS_BIG, 16, 16, -1, address_map_constructor(FUNC(dsp16_device_base::program_map), this) },
+ { "ram", ENDIANNESS_BIG, 16, yaau_bits, -1, std::move(data_map) },
+ { "exm", ENDIANNESS_BIG, 16, 16, -1 } }
+ , m_yaau_mask(u16((u32(1) << yaau_bits) - 1)), m_yaau_sign(u16(1) << (yaau_bits - 1))
+ , m_spaces{ nullptr, nullptr, nullptr }, m_direct(nullptr)
+ , m_icount(0), m_cache_mode(cache::NONE), m_phase(phase::PURGE), m_int_enable{ 0U, 0U }, m_flags(FLAGS_NONE), m_cache_ptr(0U), m_cache_limit(0U), m_cache_iterations(0U)
+ , m_exm_in(1U), m_int_in(CLEAR_LINE), m_iack_out(1U)
+ , m_ick_in(1U), m_ild_in(CLEAR_LINE), m_do_out(1U), m_ock_in(1U), m_old_in(CLEAR_LINE), m_ose_out(1U)
+ , m_psel_out(0U), m_pids_out(1U), m_pods_out(1U)
+ , m_xaau_pc(0U), m_xaau_pt(0U), m_xaau_pr(0U), m_xaau_pi(0U), m_xaau_i(0)
+ , m_yaau_r{ 0U, 0U, 0U, 0U }, m_yaau_rb(0U), m_yaau_re(0U), m_yaau_j(0), m_yaau_k(0)
+ , m_dau_x(0), m_dau_y(0), m_dau_p(0), m_dau_a{ 0, 0 }, m_dau_c{ 0, 0, 0 }, m_dau_auc(0U), m_dau_psw(0U), m_dau_temp(0)
+ , m_sio_sioc(0U), m_sio_obuf(0U), m_sio_osr(0U), m_sio_ofsr(0U)
+ , m_sio_clk(1U), m_sio_clk_div(0U), m_sio_ld(1U), m_sio_ld_div(0U), m_sio_flags(SIO_FLAGS_NONE)
+ , m_pio_pioc(0U), m_pio_pdx_in(0U), m_pio_pdx_out(0U), m_pio_pids_cnt(0U), m_pio_pods_cnt(0U)
+ , m_cache_pcbase(0U), m_st_pcbase(0U), m_st_yh(0), m_st_ah{ 0, 0 }, m_st_yl(0U), m_st_al{ 0U, 0U }
+{
+}
+
+/***********************************************************************
+ device_t implementation
+***********************************************************************/
+
+void dsp16_device_base::device_resolve_objects()
+{
+ m_iack_cb.resolve_safe();
+ m_ick_cb.resolve_safe();
+ m_ild_cb.resolve_safe();
+ m_do_cb.resolve_safe();
+ m_ock_cb.resolve_safe();
+ m_old_cb.resolve_safe();
+ m_ose_cb.resolve_safe();
-//-------------------------------------------------
-// dsp16_device - constructor
-//-------------------------------------------------
-
-dsp16_device::dsp16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : cpu_device(mconfig, DSP16, tag, owner, clock),
- m_program_config("program", ENDIANNESS_LITTLE, 16, 16, -1),
- m_data_config("data", ENDIANNESS_LITTLE, 16, 16, -1),
- m_i(0),
- m_pc(0),
- m_pt(0),
- m_pr(0),
- m_pi(0),
- m_j(0),
- m_k(0),
- m_rb(0),
- m_re(0),
- m_r0(0),
- m_r1(0),
- m_r2(0),
- m_r3(0),
- m_x(0),
- m_y(0),
- m_p(0),
- m_a0(0),
- m_a1(0),
- m_auc(0),
- m_psw(0),
- m_c0(0),
- m_c1(0),
- m_c2(0),
- m_sioc(0),
- m_srta(0),
- m_sdx(0),
- m_pioc(0),
- m_pdx0(0),
- m_pdx1(0),
- m_ppc(0),
- m_cacheStart(CACHE_INVALID),
- m_cacheEnd(CACHE_INVALID),
- m_cacheRedoNextPC(CACHE_INVALID),
- m_cacheIterations(0),
- m_program(nullptr),
- m_data(nullptr),
- m_direct(nullptr),
- m_icount(0)
-{
- // Allocate & setup
-}
-
-
-
-//-------------------------------------------------
-// device_start - start up the device
-//-------------------------------------------------
-
-void dsp16_device::device_start()
-{
- // register state with the debugger
- state_add(STATE_GENPC, "GENPC", m_pc).noshow();
- state_add(STATE_GENPCBASE, "CURPC", m_ppc).noshow();
- state_add(STATE_GENFLAGS, "GENFLAGS", m_psw).callimport().callexport().formatstr("%10s").noshow();
- state_add(DSP16_PC, "PC", m_pc);
- state_add(DSP16_I, "I", m_i);
- state_add(DSP16_PT, "PT", m_pt);
- state_add(DSP16_PR, "PR", m_pr);
- state_add(DSP16_PI, "PI", m_pi);
- state_add(DSP16_J, "J", m_j);
- state_add(DSP16_K, "K", m_k);
- state_add(DSP16_RB, "RB", m_rb);
- state_add(DSP16_RE, "RE", m_re);
- state_add(DSP16_R0, "R0", m_r0);
- state_add(DSP16_R1, "R1", m_r1);
- state_add(DSP16_R2, "R2", m_r2);
- state_add(DSP16_R3, "R3", m_r3);
- state_add(DSP16_X, "X", m_x);
- state_add(DSP16_Y, "Y", m_y);
- state_add(DSP16_P, "P", m_p);
- state_add(DSP16_A0, "A0", m_a0).mask(0xfffffffffU);
- state_add(DSP16_A1, "A1", m_a1).mask(0xfffffffffU);
- state_add(DSP16_AUC, "AUC", m_auc).formatstr("%8s");
- state_add(DSP16_PSW, "PSW", m_psw).formatstr("%16s");
- state_add(DSP16_C0, "C0", m_c0);
- state_add(DSP16_C1, "C1", m_c1);
- state_add(DSP16_C2, "C2", m_c2);
- state_add(DSP16_SIOC, "SIOC", m_sioc).formatstr("%10s");
- state_add(DSP16_SRTA, "SRTA", m_srta);
- state_add(DSP16_SDX, "SDX", m_sdx);
- state_add(DSP16_PIOC, "PIOC", m_pioc).formatstr("%16s");
- state_add(DSP16_PDX0, "PDX0", m_pdx0);
- state_add(DSP16_PDX1, "PDX1", m_pdx1);
-
- // register our state for saving
- save_item(NAME(m_i));
- save_item(NAME(m_pc));
- save_item(NAME(m_pt));
- save_item(NAME(m_pr));
- save_item(NAME(m_pi));
- save_item(NAME(m_j));
- save_item(NAME(m_k));
- save_item(NAME(m_rb));
- save_item(NAME(m_re));
- save_item(NAME(m_r0));
- save_item(NAME(m_r1));
- save_item(NAME(m_r2));
- save_item(NAME(m_r3));
- save_item(NAME(m_x));
- save_item(NAME(m_y));
- save_item(NAME(m_p));
- save_item(NAME(m_a0));
- save_item(NAME(m_a1));
- save_item(NAME(m_auc));
- save_item(NAME(m_psw));
- save_item(NAME(m_c0));
- save_item(NAME(m_c1));
- save_item(NAME(m_c2));
- save_item(NAME(m_sioc));
- save_item(NAME(m_srta));
- save_item(NAME(m_sdx));
- save_item(NAME(m_pioc));
- save_item(NAME(m_pdx0));
- save_item(NAME(m_pdx1));
- save_item(NAME(m_ppc));
- save_item(NAME(m_cacheStart));
- save_item(NAME(m_cacheEnd));
- save_item(NAME(m_cacheRedoNextPC));
- save_item(NAME(m_cacheIterations));
-
- // get our address spaces
- m_program = &space(AS_PROGRAM);
- m_data = &space(AS_DATA);
- m_direct = m_program->direct<-1>();
-
- // set our instruction counter
+ m_pio_r_cb.resolve();
+ m_pio_w_cb.resolve_safe();
+ m_pdb_w_cb.resolve_safe();
+ m_psel_cb.resolve_safe();
+ m_pids_cb.resolve_safe();
+ m_pods_cb.resolve_safe();
+}
+
+void dsp16_device_base::device_start()
+{
m_icountptr = &m_icount;
+
+ m_spaces[AS_PROGRAM] = &space(AS_PROGRAM);
+ m_spaces[AS_DATA] = &space(AS_DATA);
+ m_spaces[AS_IO] = &space(AS_IO);
+ m_direct = m_spaces[AS_PROGRAM]->direct<-1>();
+
+ state_add(STATE_GENPC, "PC", m_xaau_pc);
+ state_add(STATE_GENPCBASE, "CURPC", m_st_pcbase).noshow();
+ state_add(DSP16_PT, "PT", m_xaau_pt);
+ state_add(DSP16_PR, "PR", m_xaau_pr);
+ state_add(DSP16_PI, "PI", m_xaau_pi);
+ state_add(DSP16_I, "I", m_xaau_i).mask((s16(1) << 12) - 1).callimport();
+ state_add(DSP16_R0, "R0", m_yaau_r[0]).mask(m_yaau_mask);
+ state_add(DSP16_R1, "R1", m_yaau_r[1]).mask(m_yaau_mask);
+ state_add(DSP16_R2, "R2", m_yaau_r[2]).mask(m_yaau_mask);
+ state_add(DSP16_R3, "R3", m_yaau_r[3]).mask(m_yaau_mask);
+ state_add(DSP16_RB, "RB", m_yaau_rb).mask(m_yaau_mask);
+ state_add(DSP16_RE, "RE", m_yaau_re).mask(m_yaau_mask);
+ state_add(DSP16_J, "J", m_yaau_j).mask(m_yaau_mask).callimport();
+ state_add(DSP16_K, "K", m_yaau_k).mask(m_yaau_mask).callimport();
+ state_add(DSP16_X, "X", m_dau_x);
+ state_add(DSP16_Y, "Y", m_dau_y);
+ state_add(DSP16_P, "P", m_dau_p);
+ state_add(DSP16_A0, "A0", m_dau_a[0]).mask(DAU_A_MASK).callimport();
+ state_add(DSP16_A1, "A1", m_dau_a[1]).mask(DAU_A_MASK).callimport();
+ state_add(DSP16_C0, "C0", m_dau_c[0]);
+ state_add(DSP16_C1, "C1", m_dau_c[1]);
+ state_add(DSP16_C2, "C2", m_dau_c[2]);
+ state_add(DSP16_AUC, "AUC", m_dau_auc).mask(0x7fU);
+ state_add(DSP16_PSW, "PSW", m_dau_psw).callimport().callexport();
+ state_add(DSP16_YH, "YH", m_st_yh).noshow().callimport().callexport();
+ state_add(DSP16_A0H, "A0H", m_st_ah[0]).noshow().callimport().callexport();
+ state_add(DSP16_A1H, "A1H", m_st_ah[1]).noshow().callimport().callexport();
+ state_add(DSP16_YL, "YL", m_st_yl).noshow().callimport().callexport();
+ state_add(DSP16_A0L, "A0L", m_st_al[0]).noshow().callimport().callexport();
+ state_add(DSP16_A1L, "A1L", m_st_al[1]).noshow().callimport().callexport();
+
+ save_item(NAME(m_cache_mode));
+ save_item(NAME(m_phase));
+ save_item(NAME(m_int_enable));
+ save_item(NAME(m_flags));
+ save_item(NAME(m_cache_ptr));
+ save_item(NAME(m_cache_limit));
+ save_item(NAME(m_cache_iterations));
+ save_item(NAME(m_cache));
+ save_item(NAME(m_rom_data));
+
+ save_item(NAME(m_exm_in));
+ save_item(NAME(m_int_in));
+ save_item(NAME(m_iack_out));
+
+ save_item(NAME(m_ick_in));
+ save_item(NAME(m_ild_in));
+ save_item(NAME(m_do_out));
+ save_item(NAME(m_ock_in));
+ save_item(NAME(m_old_in));
+ save_item(NAME(m_ose_out));
+
+ save_item(NAME(m_psel_out));
+ save_item(NAME(m_pids_out));
+ save_item(NAME(m_pods_out));
+
+ save_item(NAME(m_xaau_pc));
+ save_item(NAME(m_xaau_pt));
+ save_item(NAME(m_xaau_pr));
+ save_item(NAME(m_xaau_pi));
+ save_item(NAME(m_xaau_i));
+
+ save_item(NAME(m_yaau_r));
+ save_item(NAME(m_yaau_rb));
+ save_item(NAME(m_yaau_re));
+ save_item(NAME(m_yaau_j));
+ save_item(NAME(m_yaau_k));
+
+ save_item(NAME(m_dau_x));
+ save_item(NAME(m_dau_y));
+ save_item(NAME(m_dau_p));
+ save_item(NAME(m_dau_a));
+ save_item(NAME(m_dau_c));
+ save_item(NAME(m_dau_auc));
+ save_item(NAME(m_dau_psw));
+ save_item(NAME(m_dau_temp));
+
+ save_item(NAME(m_sio_sioc));
+ save_item(NAME(m_sio_obuf));
+ save_item(NAME(m_sio_osr));
+ save_item(NAME(m_sio_ofsr));
+ save_item(NAME(m_sio_clk));
+ save_item(NAME(m_sio_clk_div));
+ save_item(NAME(m_sio_ld));
+ save_item(NAME(m_sio_ld_div));
+ save_item(NAME(m_sio_flags));
+
+ save_item(NAME(m_pio_pioc));
+ save_item(NAME(m_pio_pdx_in));
+ save_item(NAME(m_pio_pdx_out));
+ save_item(NAME(m_pio_pids_cnt));
+ save_item(NAME(m_pio_pods_cnt));
+
+ save_item(NAME(m_cache_pcbase));
+ save_item(NAME(m_st_pcbase));
+
+ external_memory_enable(*m_spaces[AS_PROGRAM], !m_exm_in);
}
+void dsp16_device_base::device_reset()
+{
+ cpu_device::device_reset();
+
+ m_cache_mode = cache::NONE;
+ m_phase = phase::PURGE;
+ std::fill(std::begin(m_int_enable), std::end(m_int_enable), 0U);
+ m_flags = FLAGS_NONE;
+ m_cache_ptr = 0U;
+ m_xaau_pc = 0U;
+ m_yaau_rb = 0U;
+ m_yaau_re = 0U;
+ m_sio_sioc = 0U;
+ m_sio_ofsr = 0U;
+ m_sio_clk = 1U;
+ m_sio_clk_div = 0U;
+ m_pio_pioc = 0x0008U;
+ m_pio_pids_cnt = 0U;
+ m_pio_pods_cnt = 0U;
+ m_st_pcbase = 0U;
+
+ // interrupt reset outputs
+ if (!m_iack_out)
+ {
+ LOGINT("DSP16: de-asserting IACK for reset\n");
+ m_iack_cb(m_iack_out = 1U);
+ }
-//-------------------------------------------------
-// device_reset - reset the device
-//-------------------------------------------------
+ // SIO reset outputs
+ m_ick_cb(1); // actually high-impedance
+ m_ild_cb(1); // actually high-impedance
+ m_do_cb(m_do_out = 1U); // actually high-impedance
+ m_ock_cb(1); // actually high-impedance
+ m_old_cb(1); // actually high-impedance
+ if (!m_ose_out)
+ m_ose_cb(m_ose_out = 1U);
-void dsp16_device::device_reset()
+ // PIO reset outputs
+ m_pdb_w_cb(machine().dummy_space(), m_psel_out, 0xffffU, 0x0000U);
+ if (!m_pids_out)
+ {
+ LOGPIO("DSP16: de-asserting PIDS for reset\n");
+ m_pids_cb(m_pids_out = 1U); // actually high-impedance
+ }
+ if (!m_pods_out)
+ {
+ LOGPIO("DSP16: de-asserting PODS for reset\n");
+ m_pods_cb(m_pods_out = 1U); // actually high-impedance
+ }
+}
+
+/***********************************************************************
+ device_execute_interface implementation
+***********************************************************************/
+
+void dsp16_device_base::execute_run()
{
- // Page 7-5
- m_pc = 0x0000;
- m_pi = 0x0000;
- m_sioc = 0x0000; // (page 5-4)
+ while (0 < m_icount)
+ {
+ // execute one cycle of an instruction
+ switch (m_cache_mode)
+ {
+ case cache::NONE:
+ case cache::LOAD:
+ execute_one_rom();
+ break;
+ case cache::EXECUTE:
+ execute_one_cache();
+ break;
+ }
+ --m_icount;
- // SRTA is unaltered by reset
- m_pioc = 0x0008;
- m_rb = 0x0000;
- m_re = 0x0000;
+ // step the serial I/O clock divider
+ if (m_sio_clk_div)
+ {
+ --m_sio_clk_div;
+ }
+ else
+ {
+ bool const active(!m_sio_clk);
+ m_sio_clk = active ? 1U : 0U;
+ if (sio_ick_active())
+ {
+ if (active)
+ sio_ick_active_edge();
+ m_ick_cb(m_sio_clk);
+ }
+ if (sio_ock_active())
+ {
+ m_ock_cb(m_sio_clk);
+ if (active)
+ sio_ock_active_edge();
+ }
+ switch ((m_sio_sioc >> 7) & 0x0003U)
+ {
+ case 0x0: m_sio_clk_div = (4 / 4) - 1; break; // CKI÷4
+ case 0x1: m_sio_clk_div = (12 / 4) - 1; break; // CKI÷12
+ case 0x2: m_sio_clk_div = (16 / 4) - 1; break; // CKI÷16
+ case 0x3: m_sio_clk_div = (20 / 4) - 1; break; // CKI÷20
+ }
+ }
- // AUC is not affected by reset
- m_ppc = m_pc;
+ // udpate parallel input strobe
+ if (m_pio_pids_cnt)
+ {
+ assert(!m_pids_out);
+ if (!--m_pio_pids_cnt)
+ {
+ if (!m_pio_r_cb.isnull())
+ m_pio_pdx_in = m_pio_r_cb(machine().dummy_space(), m_psel_out, 0xffffU);
+ m_pids_cb(m_pids_out = 1U);
+ LOGPIO("DSP16: PIO read active edge PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, m_pio_pdx_in, m_st_pcbase);
+ }
+ }
+ else
+ {
+ assert(m_pids_out);
+ }
- // Hacky cache emulation.
- m_cacheStart = CACHE_INVALID;
- m_cacheEnd = CACHE_INVALID;
- m_cacheRedoNextPC = CACHE_INVALID;
- m_cacheIterations = 0;
+ // udpate parallel output strobe
+ if (m_pio_pods_cnt)
+ {
+ assert(!m_pods_out);
+ if (!--m_pio_pods_cnt)
+ {
+ LOGPIO("DSP16: PIO write active edge PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, m_pio_pdx_out, m_st_pcbase);
+ m_pods_cb(1U);
+ m_pio_w_cb(machine().dummy_space(), m_psel_out, m_pio_pdx_out, 0xffffU);
+ m_pods_out = 1U;
+ m_pdb_w_cb(machine().dummy_space(), m_psel_out, 0xffffU, 0x0000U);
+ }
+ }
+ else
+ {
+ assert(m_pods_out);
+ }
+ }
}
+void dsp16_device_base::execute_set_input(int inputnum, int state)
+{
+ switch (inputnum)
+ {
+ case DSP16_INT_LINE:
+ m_int_in = state;
+ break;
+ case DSP16_ICK_LINE:
+ if (((CLEAR_LINE == state) ? 0U : 1U) != m_ick_in)
+ {
+ if (!sio_ick_active())
+ {
+ if (CLEAR_LINE != state)
+ sio_ick_active_edge();
+ }
+ else
+ {
+ logerror("DSP16: warning: ignoring ICK input in active mode (PC = %04X)\n", m_st_pcbase);
+ }
+ m_ick_in = (ASSERT_LINE == state) ? 1U : 0U;
+ }
+ break;
+ case DSP16_ILD_LINE:
+ if (sio_ild_active())
+ logerror("DSP16: warning: ignoring ILD input in active mode (PC = %04X)\n", m_st_pcbase);
+ m_ild_in = state;
+ break;
+ case DSP16_OCK_LINE:
+ if (((CLEAR_LINE == state) ? 0U : 1U) != m_ock_in)
+ {
+ if (!sio_ock_active())
+ {
+ if (CLEAR_LINE != state)
+ sio_ock_active_edge();
+ }
+ else
+ {
+ logerror("DSP16: warning: ignoring OCK input in active mode (PC = %04X)\n", m_st_pcbase);
+ }
+ m_ock_in = (ASSERT_LINE == state) ? 1U : 0U;
+ }
+ break;
+ case DSP16_OLD_LINE:
+ if (sio_old_active())
+ logerror("DSP16: warning: ignoring OLD input in active mode (PC = %04X)\n", m_st_pcbase);
+ m_old_in = state;
+ break;
+ }
+}
-//-------------------------------------------------
-// memory_space_config - return the configuration
-// of the specified address space, or nullptr if
-// the space doesn't exist
-//-------------------------------------------------
+/***********************************************************************
+ device_memory_interface implementation
+***********************************************************************/
-device_memory_interface::space_config_vector dsp16_device::memory_space_config() const
+device_memory_interface::space_config_vector dsp16_device_base::memory_space_config() const
{
- return space_config_vector {
- std::make_pair(AS_PROGRAM, &m_program_config),
- std::make_pair(AS_DATA, &m_data_config)
- };
+ return space_config_vector{
+ std::make_pair(AS_PROGRAM, &m_space_config[AS_PROGRAM]),
+ std::make_pair(AS_DATA, &m_space_config[AS_DATA]),
+ std::make_pair(AS_IO, &m_space_config[AS_IO]) };
}
+/***********************************************************************
+ device_state_interface implementation
+***********************************************************************/
-//-------------------------------------------------
-// state_string_export - export state as a string
-// for the debugger
-//-------------------------------------------------
+void dsp16_device_base::state_import(device_state_entry const &entry)
+{
+ switch (entry.index())
+ {
+ // extend signed registers that aren't a power-of-two size
+ case DSP16_I:
+ m_xaau_i = (m_xaau_i & XAAU_I_MASK) | ((m_xaau_i & XAAU_I_SIGN) ? XAAU_I_EXT : 0);
+ break;
+ case DSP16_J:
+ m_yaau_j = (m_yaau_j & m_yaau_mask) | ((m_yaau_j & m_yaau_sign) ? ~m_yaau_mask : 0);
+ break;
+ case DSP16_K:
+ m_yaau_k = (m_yaau_k & m_yaau_mask) | ((m_yaau_k & m_yaau_sign) ? ~m_yaau_mask : 0);
+ break;
+ case DSP16_A0:
+ m_dau_a[0] = (m_dau_a[0] & DAU_A_MASK) | ((m_dau_a[0] & DAU_A_SIGN) ? DAU_A_EXT : 0);
+ break;
+ case DSP16_A1:
+ m_dau_a[1] = (m_dau_a[1] & DAU_A_MASK) | ((m_dau_a[1] & DAU_A_SIGN) ? DAU_A_EXT : 0);
+ break;
+
+ // guard bits of accumulators are accessible via status word
+ case DSP16_PSW:
+ m_dau_a[0] = u64(u32(m_dau_a[0])) | (u64(m_dau_psw & 0x000fU) << 32) | (BIT(m_dau_psw, 3) ? DAU_A_EXT : 0U);
+ m_dau_a[1] = u64(u32(m_dau_a[1])) | (u64(m_dau_psw & 0x01e0U) << 27) | (BIT(m_dau_psw, 8) ? DAU_A_EXT : 0U);
+ break;
-void dsp16_device::state_string_export(const device_state_entry &entry, std::string &str) const
+ // put partial registers in the appropriate places
+ case DSP16_YH:
+ m_dau_y = (s32(m_st_yh) << 16) | (m_dau_y & ((s32(1) << 16) - 1));
+ break;
+ case DSP16_A0H:
+ m_dau_a[0] = (s32(m_st_ah[0]) << 16) | s32(m_dau_a[0] & ((s32(1) << 16) - 1));
+ break;
+ case DSP16_A1H:
+ m_dau_a[1] = (s32(m_st_ah[1]) << 16) | s32(m_dau_a[1] & ((s32(1) << 16) - 1));
+ break;
+ case DSP16_YL:
+ m_dau_y = (m_dau_y & ~((s32(1) << 16) - 1)) | u32(m_st_yl);
+ break;
+ case DSP16_A0L:
+ m_dau_a[0] = (m_dau_a[0] & ~((s64(1) << 16) - 1)) | u64(m_st_al[0]);
+ break;
+ case DSP16_A1L:
+ m_dau_a[1] = (m_dau_a[1] & ~((s64(1) << 16) - 1)) | u64(m_st_al[1]);
+ break;
+ }
+}
+
+void dsp16_device_base::state_export(device_state_entry const &entry)
{
switch (entry.index())
{
- case STATE_GENFLAGS:
- str = "(below)";
+ // guard bits of accumulators are accessible via status word
+ case DSP16_PSW:
+ m_dau_psw = (m_dau_psw & 0xfe10U) | (u16(u64(m_dau_a[0]) >> 32) & 0x000fU) | (u16(u64(m_dau_a[1]) >> 27) & 0x01e0U);
+ break;
+
+ // put partial registers in the appropriate places
+ case DSP16_YH:
+ m_st_yh = m_dau_y >> 16;
+ break;
+ case DSP16_A0H:
+ m_st_ah[0] = u16(u64(m_dau_a[0]) >> 16);
+ break;
+ case DSP16_A1H:
+ m_st_ah[1] = u16(u64(m_dau_a[1]) >> 16);
+ break;
+ case DSP16_YL:
+ m_st_yl = u16(u32(m_dau_y));
+ break;
+ case DSP16_A0L:
+ m_st_al[0] = u16(u64(m_dau_a[0]));
+ break;
+ case DSP16_A1L:
+ m_st_al[1] = u16(u64(m_dau_a[1]));
+ break;
+ }
+}
+
+/***********************************************************************
+ device_disasm_interface implementation
+***********************************************************************/
+
+util::disasm_interface *dsp16_device_base::create_disassembler()
+{
+ return new dsp16a_disassembler;
+}
+
+template <offs_t Base> READ16_MEMBER(dsp16_device_base::external_memory_r)
+{
+ return m_spaces[AS_IO]->read_word(Base + offset, mem_mask);
+}
+
+/***********************************************************************
+ internal address maps
+***********************************************************************/
+
+void dsp16_device_base::program_map(address_map &map)
+{
+ map.global_mask(0xffff);
+ map.unmap_value_high();
+}
+
+/***********************************************************************
+ instruction execution
+***********************************************************************/
+
+inline void dsp16_device_base::execute_one_rom()
+{
+ u16 const op(m_cache[m_cache_ptr]);
+ bool const cache_load(cache::LOAD == m_cache_mode);
+ bool const last_cache_load(cache_load && (m_cache_ptr == m_cache_limit));
+ u16 const cache_next((m_cache_ptr + (cache_load ? 1 : 0)) & 0x0fU);
+ u16 *fetch_target(&m_cache[cache_next]);
+ u16 fetch_addr(0U);
+ flags predicate(FLAGS_PRED_NONE);
+
+ switch (m_phase)
+ {
+ case phase::PURGE:
+ fetch_addr = m_xaau_pc;
+ m_phase = phase::OP1;
break;
- case DSP16_AUC:
+ case phase::OP1:
+ if (machine().debug_flags & DEBUG_FLAG_ENABLED)
+ debugger_instruction_hook(this, m_st_pcbase);
+
+ // IACK is updated for the next instruction
+ switch (m_flags & FLAGS_IACK_MASK)
+ {
+ case FLAGS_IACK_SET:
+ if (m_iack_out)
+ {
+ LOGINT("DSP16: asserting IACK (PC = %04X)\n", m_st_pcbase);
+ m_iack_cb(m_iack_out = 0U);
+ standard_irq_callback(DSP16_INT_LINE);
+ }
+ break;
+ case FLAGS_IACK_CLEAR:
+ if (!m_iack_out)
+ {
+ LOGINT("DSP16: de-asserting IACK (PC = %04X)\n", m_st_pcbase);
+ m_iack_cb(m_iack_out = 1U);
+ m_pio_pioc &= 0xfffeU;
+ }
+ break;
+ default:
+ break;
+ }
+ set_iack(FLAGS_IACK_NONE);
+
+ // if we're not servicing an interrupt or caching
+ if (m_iack_out && (cache::NONE == m_cache_mode))
{
- std::string alignString;
- const uint8_t align = m_auc & 0x03;
- switch (align)
+ // TODO: is INT sampled on any instruction or only interruptible instructions?
+ // if an unmasked interrupt is pending
+ if ((m_pio_pioc & m_int_enable[0] & 0x001eU) || (BIT(m_int_enable[0], 0) && (CLEAR_LINE != m_int_in)))
{
- case 0x00: alignString = "xy"; break;
- case 0x01: alignString = "/4"; break;
- case 0x02: alignString = "x4"; break;
- case 0x03: alignString = ",,"; break;
+ // if the current instruction is interruptible
+ if (op_interruptible(op))
+ {
+ if (pio_int_enable() && (CLEAR_LINE != m_int_in))
+ {
+ if (ASSERT_LINE != m_int_in)
+ m_int_in = CLEAR_LINE;
+ m_pio_pioc |= 0x0001U;
+ }
+ LOGINT(
+ "DSP16: servicing interrupts%s%s%s%s%s (PC = %04X)\n",
+ (pio_ibf_enable() && pio_ibf_status()) ? " IBF" : "",
+ (pio_obe_enable() && pio_obe_status()) ? " OBE" : "",
+ (pio_pids_enable() && pio_pids_status()) ? " PIDS" : "",
+ (pio_pods_enable() && pio_pods_status()) ? " PODS" : "",
+ (pio_int_enable() && pio_int_status()) ? " INT" : "",
+ m_st_pcbase);
+ set_iack(FLAGS_IACK_SET);
+ fetch_addr = (m_xaau_pc & 0xf000U) | ((m_xaau_pc + 1) & 0x0fffU);
+ m_int_enable[0] = m_int_enable[1];
+ m_xaau_pc = 0x0001U;
+ m_phase = phase::PURGE;
+ break;
+ }
+ }
+ }
+
+ // normal opcode execution
+ fetch_addr = set_xaau_pc_offset(m_xaau_pc + 1);
+ m_int_enable[0] = m_int_enable[1];
+ switch (op >> 11)
+ {
+ case 0x00: // goto JA
+ case 0x01:
+ case 0x10: // call JA
+ case 0x11:
+ if (check_predicate())
+ {
+ if (BIT(op, 15))
+ m_xaau_pr = m_xaau_pc;
+ set_xaau_pc_offset(op_ja(op));
+ }
+ m_phase = phase::PURGE;
+ break;
+
+ case 0x02: // R = M
+ case 0x03:
+ yaau_short_immediate_load(op);
+ break;
+
+ case 0x04: // F1 ; Y = a1[l]
+ case 0x1c: // F1 ; Y = a0[l]
+ fetch_target = nullptr;
+ m_phase = phase::OP2;
+ break;
+
+ case 0x06: // F1 ; Y
+ op_dau_ad(op) = dau_f1(op);
+ yaau_read(op);
+ break;
+
+ case 0x07: // F1 ; aT[l] = Y
+ op_dau_ad(op) = dau_f1(op);
+ set_dau_at(op, yaau_read(op));
+ break;
+
+ case 0x08: // aT = R
+ assert(!(op & 0x000fU)); // reserved field?
+ fetch_target = nullptr;
+ set_dau_at(op, get_r(op));
+ m_phase = phase::OP2;
+ break;
+
+ case 0x09: // R = a0
+ case 0x0b: // R = a1
+ {
+ assert(!(op & 0x040fU)); // reserved fields?
+ fetch_target = nullptr;
+ s64 a(m_dau_a[BIT(op, 12)]);
+ if (!BIT(m_dau_auc, 2 + BIT(op, 12)))
+ a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
+ set_r(op, u16(u64(a) >> 16));
+ m_phase = phase::OP2;
+ }
+ break;
+
+ case 0x0a: // R = N
+ assert(!(op & 0x040fU)); // reserved fields?
+ m_phase = phase::OP2;
+ fetch_target = &m_rom_data;
+ break;
+
+ case 0x0c: // Y = R
+ assert(!(op & 0x0400U)); // reserved field?
+ fetch_target = nullptr;
+ m_phase = phase::OP2;
+ break;
+
+ case 0x0e: // do K { instr1...instrIN } # redo K
+ {
+ u16 const ni(op_ni(op));
+ if (ni)
+ {
+ m_cache_mode = cache::LOAD;
+ fetch_target = &m_cache[m_cache_ptr = 1U];
+ m_cache_limit = ni;
+ m_cache_pcbase = m_st_pcbase;
+ }
+ else
+ {
+ fetch_target = nullptr;
+ m_cache_mode = cache::EXECUTE;
+ m_phase = phase::PREFETCH;
+ m_cache_ptr = 1U;
+ }
+ m_cache_iterations = op_k(op);
+ assert(m_cache_iterations >= 2U); // p3-25: "The iteration count can be between 2 and 127, inclusive"
+ }
+ break;
+
+ case 0x0f: // R = Y
+ assert(!(op & 0x0400U)); // reserved field?
+ fetch_target = nullptr;
+ set_r(op, yaau_read(op));
+ m_phase = phase::OP2;
+ break;
+
+ case 0x12: // ifc CON F2
+ ++m_dau_c[1];
+ if (op_dau_con(op))
+ {
+ op_dau_ad(op) = dau_f2(op);
+ m_dau_c[2] = m_dau_c[1];
+ }
+ break;
+
+ case 0x13: // if CON F2
+ if (op_dau_con(op))
+ op_dau_ad(op) = dau_f2(op);
+ break;
+
+ case 0x14: // F1 ; Y = y[l]
+ fetch_target = nullptr;
+ op_dau_ad(op) = dau_f1(op);
+ m_phase = phase::OP2;
+ break;
+
+ case 0x15: // F1 ; Z : y[l]
+ fetch_target = nullptr;
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_temp = u16(u32(m_dau_y) >> (op_x(op) ? 16 : 0));
+ set_dau_y(op, yaau_read(op));
+ m_phase = phase::OP2;
+ break;
+
+ case 0x16: // F1 ; x = Y
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_x = yaau_read(op);
+ break;
+
+ case 0x17: // F1 ; y[l] = Y
+ op_dau_ad(op) = dau_f1(op);
+ set_dau_y(op, yaau_read(op));
+ break;
+
+ case 0x18: // goto B
+ assert(!(op & 0x00ffU)); // reserved field?
+ switch (op_b(op))
+ {
+ case 0x0: // return
+ if (check_predicate())
+ m_xaau_pc = m_xaau_pr;
+ break;
+ case 0x1: // ireturn
+ if (m_iack_out)
+ logerror("DSP16: ireturn when not servicing interrupt (PC = %04X)\n", m_st_pcbase);
+ LOGINT("DSP16: return from interrupt (PC = %04X)\n", m_st_pcbase);
+ set_iack(FLAGS_IACK_CLEAR);
+ m_xaau_pc = m_xaau_pi;
+ break;
+ case 0x2: // goto pt
+ if (check_predicate())
+ m_xaau_pc = m_xaau_pt;
+ break;
+ case 0x3: // call pt
+ if (check_predicate())
+ {
+ m_xaau_pr = m_xaau_pc;
+ m_xaau_pc = m_xaau_pt;
+ }
+ break;
+ case 0x4: // Reserved
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ throw emu_fatalerror("DSP16: reserved B value %01X (PC = %04X)\n", op_b(op), m_st_pcbase);
+ }
+ if (m_iack_out)
+ m_xaau_pi = m_xaau_pc;
+ m_phase = phase::PURGE;
+ break;
+
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i]
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
+ {
+ assert(!(op & 0x000fU)); // reserved field?
+ s64 const d(dau_f1(op));
+ s64 a(m_dau_a[BIT(op, 12)]);
+ // FIXME: is saturation applied when transferring a to y?
+ m_dau_y = u32(u64(a));
+ op_dau_ad(op) = d;
+ fetch_target = nullptr;
+ m_rom_data = m_spaces[AS_PROGRAM]->read_word(m_xaau_pt);
+ m_phase = phase::OP2;
+ }
+ break;
+
+ case 0x1a: // if CON # icall
+ // FIXME: icall is a special case of this op
+ assert(!(op & 0x07e0U)); // reserved field?
+ predicate = op_dau_con(op) ? FLAGS_PRED_TRUE : FLAGS_PRED_FALSE;
+ break;
+
+ case 0x1e: // Reserved
+ throw emu_fatalerror("DSP16: reserved op %u (PC = %04X)\n", op >> 11, m_st_pcbase);
+ break;
+
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_y = (u32(u16(yaau_read(op))) << 16) | u32(BIT(m_dau_psw, 6) ? u16(u32(m_dau_y)) : u16(0));
+ fetch_target = nullptr;
+ m_rom_data = m_spaces[AS_PROGRAM]->read_word(m_xaau_pt);
+ m_phase = phase::OP2;
+ break;
+
+ default:
+ throw emu_fatalerror("DSP16: unimplemented op %u (PC = %04X)\n", op >> 11, m_st_pcbase);
+ }
+
+ if (cache_load && (phase::OP1 == m_phase))
+ {
+ // if the last instruction loaded to the cache completes in a single cycle, there's an extra cycle for a data fetch
+ if (last_cache_load)
+ {
+ fetch_target = nullptr;
+ m_cache_mode = cache::EXECUTE;
+ m_phase = phase::PREFETCH;
+ m_cache_ptr = 1U;
+ --m_cache_iterations;
+ }
+ else
+ {
+ m_cache_ptr = cache_next;
}
- str = string_format("%c%c%c%c%c%s",
- m_auc & 0x40 ? 'Y':'.',
- m_auc & 0x20 ? '1':'.',
- m_auc & 0x10 ? '0':'.',
- m_auc & 0x08 ? '1':'.',
- m_auc & 0x04 ? '0':'.',
- alignString);
}
break;
- case DSP16_PSW:
- str = string_format("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
- m_psw & 0x8000 ? 'M':'.',
- m_psw & 0x4000 ? 'E':'.',
- m_psw & 0x2000 ? 'L':'.',
- m_psw & 0x1000 ? 'V':'.',
- m_psw & 0x0800 ? ',':',',
- m_psw & 0x0400 ? ',':',',
- m_psw & 0x0200 ? 'O':'.',
- m_psw & 0x0100 ? '1':'.',
- m_psw & 0x0080 ? '1':'.',
- m_psw & 0x0040 ? '1':'.',
- m_psw & 0x0020 ? '1':'.',
- m_psw & 0x0010 ? 'O':'.',
- m_psw & 0x0008 ? '1':'.',
- m_psw & 0x0004 ? '1':'.',
- m_psw & 0x0002 ? '1':'.',
- m_psw & 0x0001 ? '1':'.');
- break;
-
- case DSP16_PIOC:
+ case phase::OP2:
+ m_phase = phase::OP1;
+ switch (op >> 11)
{
- std::string strobeString;
- const uint8_t strobe = (m_pioc & 0x6000) >> 13;
- switch (strobe)
+ case 0x04: // F1 ; Y = a1[l]
+ case 0x1c: // F1 ; Y = a0[l]
{
- case 0x00: strobeString = "1T"; break;
- case 0x01: strobeString = "2T"; break;
- case 0x02: strobeString = "3T"; break;
- case 0x03: strobeString = "4T"; break;
+ s64 a(m_dau_a[BIT(~op, 14)]);
+ bool const sat(!BIT(m_dau_auc, 2 + BIT(~op, 14)));
+ if (sat)
+ a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
+ yaau_write(op, u16(u64(a) >> (op_x(op) ? 16 : 0)));
+ op_dau_ad(op) = dau_f1(op);
}
- str = string_format("%c%s%c%c%c%c%c%c%c%c%c%c%c%c%c",
- m_pioc & 0x8000 ? 'I':'.',
- strobeString,
- m_pioc & 0x1000 ? 'O':'I',
- m_pioc & 0x0800 ? 'O':'I',
- m_pioc & 0x0400 ? 'S':'.',
- m_pioc & 0x0200 ? 'I':'.',
- m_pioc & 0x0100 ? 'O':'.',
- m_pioc & 0x0080 ? 'P':'.',
- m_pioc & 0x0040 ? 'P':'.',
- m_pioc & 0x0020 ? 'I':'.',
- m_pioc & 0x0010 ? 'I':'.',
- m_pioc & 0x0008 ? 'O':'.',
- m_pioc & 0x0004 ? 'P':'.',
- m_pioc & 0x0002 ? 'P':'.',
- m_pioc & 0x0001 ? 'I':'.');
+ break;
+
+ case 0x08: // aT = R
+ case 0x09: // R = a0
+ case 0x0b: // R = a1
+ break;
+
+ case 0x0a: // R = N
+ set_xaau_pc_offset(m_xaau_pc + 1);
+ set_r(op, m_rom_data);
+ break;
+
+ case 0x0c: // Y = R
+ yaau_write(op, get_r(op));
+ break;
+
+ case 0x0f: // R = Y
+ break;
+
+ case 0x14: // F1 ; Y = y[l]
+ yaau_write(op, u16(u32(m_dau_y) >> (op_x(op) ? 16 : 0)));
+ break;
+
+ case 0x15: // F1 ; Z : y[l]
+ yaau_write_z(op);
+ break;
+
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i]
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ xaau_increment_pt(op_xaau_increment(op));
+ m_dau_x = m_rom_data;
+ break;
+
+ default:
+ throw emu_fatalerror("DSP16: op %u doesn't take two cycles to run from ROM\n", op >> 11);
+ }
+
+ if (last_cache_load)
+ {
+ fetch_target = nullptr;
+ m_cache_mode = cache::EXECUTE;
+ m_cache_ptr = 1U;
+ --m_cache_iterations;
+ overlap_rom_data_read();
+ }
+ else
+ {
+ fetch_addr = m_xaau_pc;
+ if (cache_load)
+ m_cache_ptr = cache_next;
}
break;
- // Placeholder for a better view later (TODO)
- case DSP16_SIOC:
+ default:
+ throw emu_fatalerror("DSP16: inappropriate phase for ROM execution\n");
+ }
+
+ if (FLAGS_PRED_NONE != (m_flags & FLAGS_PRED_MASK))
+ throw emu_fatalerror("DSP16: predicate applied to ineligible op %u (PC = %04X)\n", op >> 11, m_st_pcbase);
+ set_predicate(predicate);
+
+ if (fetch_target)
+ *fetch_target = m_direct->read_word(fetch_addr);
+
+ if (phase::OP1 == m_phase)
+ {
+ if (cache::EXECUTE != m_cache_mode)
+ m_st_pcbase = m_xaau_pc;
+ else
+ m_st_pcbase = (m_cache_pcbase & 0xf000U) | ((m_cache_pcbase + m_cache_ptr) & 0x0fffU);
+ }
+}
+
+inline void dsp16_device_base::execute_one_cache()
+{
+ u16 const op(m_cache[m_cache_ptr]);
+ bool const at_limit(m_cache_ptr == m_cache_limit);
+ bool const last_instruction(at_limit && (1U == m_cache_iterations));
+ switch (m_phase)
+ {
+ case phase::OP1:
+ if (machine().debug_flags & DEBUG_FLAG_ENABLED)
+ debugger_instruction_hook(this, m_st_pcbase);
+ m_int_enable[0] = m_int_enable[1];
+ switch (op >> 11)
{
- std::string clkString;
- const uint8_t clk = (m_sioc & 0x0180) >> 7;
- switch (clk)
+ case 0x02: // R = M
+ case 0x03:
+ yaau_short_immediate_load(op);
+ break;
+
+ case 0x04: // F1 ; Y = a1[l]
+ case 0x1c: // F1 ; Y = a0[l]
+ m_phase = phase::OP2;
+ break;
+
+ case 0x06: // F1 ; Y
+ op_dau_ad(op) = dau_f1(op);
+ yaau_read(op);
+ break;
+
+ case 0x07: // F1 ; aT[l] = Y
+ op_dau_ad(op) = dau_f1(op);
+ set_dau_at(op, yaau_read(op));
+ break;
+
+ case 0x08: // aT = R
+ assert(!(op & 0x000fU)); // reserved field?
+ set_dau_at(op, get_r(op));
+ m_phase = phase::OP2;
+ break;
+
+ case 0x09: // R = a0
+ case 0x0b: // R = a1
{
- case 0x00: clkString = "/4"; break;
- case 0x01: clkString = "12"; break;
- case 0x02: clkString = "16"; break;
- case 0x03: clkString = "20"; break;
+ assert(!(op & 0x040fU)); // reserved fields?
+ s64 a(m_dau_a[BIT(op, 12)]);
+ if (!BIT(m_dau_auc, 2 + BIT(op, 12)))
+ a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
+ set_r(op, u16(u64(a) >> 16));
+ m_phase = phase::OP2;
}
- str = string_format("%c%s%c%c%c%c%c%c%c",
- m_sioc & 0x0200 ? 'I':'O',
- clkString,
- m_sioc & 0x0040 ? 'L':'M',
- m_sioc & 0x0020 ? 'I':'O',
- m_sioc & 0x0010 ? 'I':'O',
- m_sioc & 0x0008 ? 'I':'O',
- m_sioc & 0x0004 ? 'I':'O',
- m_sioc & 0x0002 ? '2':'1',
- m_sioc & 0x0001 ? '2':'1');
+ break;
+
+ case 0x0c: // Y = R
+ assert(!(op & 0x0400U)); // reserved field?
+ m_phase = phase::OP2;
+ break;
+
+ case 0x0f: // R = Y
+ assert(!(op & 0x0400U)); // reserved field?
+ set_r(op, yaau_read(op));
+ m_phase = phase::OP2;
+ break;
+
+ case 0x12: // ifc CON F2
+ ++m_dau_c[1];
+ if (op_dau_con(op))
+ {
+ op_dau_ad(op) = dau_f2(op);
+ m_dau_c[2] = m_dau_c[1];
+ }
+ break;
+
+ case 0x13: // if CON F2
+ if (op_dau_con(op))
+ op_dau_ad(op) = dau_f2(op);
+ break;
+
+ case 0x14: // F1 ; Y = y[l]
+ op_dau_ad(op) = dau_f1(op);
+ m_phase = phase::OP2;
+ break;
+
+ case 0x15: // F1 ; Z : y[l]
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_temp = u16(u32(m_dau_y) >> (op_x(op) ? 16 : 0));
+ set_dau_y(op, yaau_read(op));
+ m_phase = phase::OP2;
+ break;
+
+ case 0x16: // F1 ; x = Y
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_x = yaau_read(op);
+ break;
+
+ case 0x17: // F1 ; y[l] = Y
+ op_dau_ad(op) = dau_f1(op);
+ set_dau_y(op, yaau_read(op));
+ break;
+
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i]
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
+ {
+ assert(!(op & 0x000fU)); // reserved field?
+ s64 const d(dau_f1(op));
+ s64 a(m_dau_a[BIT(op, 12)]);
+ // FIXME: is saturation applied when transferring a to y?
+ m_dau_y = u32(u64(a));
+ op_dau_ad(op) = d;
+ if (last_instruction)
+ {
+ m_rom_data = m_direct->read_word(m_xaau_pt);
+ m_phase = phase::OP2;
+ }
+ else
+ {
+ xaau_increment_pt(op_xaau_increment(op));
+ m_dau_x = m_rom_data;
+ }
+ }
+ break;
+
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_y = (u32(u16(yaau_read(op))) << 16) | u32(BIT(m_dau_psw, 6) ? u16(u32(m_dau_y)) : u16(0));
+ if (last_instruction)
+ {
+ m_rom_data = m_direct->read_word(m_xaau_pt);
+ m_phase = phase::OP2;
+ }
+ else
+ {
+ xaau_increment_pt(op_xaau_increment(op));
+ m_dau_x = m_rom_data;
+ }
+ break;
+
+ default:
+ throw emu_fatalerror("DSP16: inelligible op %u in cache (PC = %04X)\n", op >> 11, m_st_pcbase);
}
break;
+
+ case phase::OP2:
+ m_phase = phase::OP1;
+ switch (op >> 11)
+ {
+ case 0x04: // F1 ; Y = a1[l]
+ case 0x1c: // F1 ; Y = a0[l]
+ {
+ s64 a(m_dau_a[BIT(~op, 14)]);
+ if (!BIT(m_dau_auc, 2 + BIT(~op, 14)))
+ a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
+ yaau_write(op, u16(u64(a) >> (op_x(op) ? 16 : 0)));
+ op_dau_ad(op) = dau_f1(op);
+ }
+ break;
+
+ case 0x08: // aT = R
+ case 0x09: // R = a0
+ case 0x0b: // R = a1
+ break;
+
+ case 0x0c: // Y = R
+ yaau_write(op, get_r(op));
+ break;
+
+ case 0x0f: // R = Y
+ break;
+
+ case 0x14: // F1 ; Y = y[l]
+ yaau_write(op, u16(u32(m_dau_y) >> (op_x(op) ? 16 : 0)));
+ break;
+
+ case 0x15: // F1 ; Z : y[l]
+ yaau_write_z(op);
+ break;
+
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i]
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ assert(last_instruction);
+ xaau_increment_pt(op_xaau_increment(op));
+ m_dau_x = m_rom_data;
+ break;
+
+ default:
+ throw emu_fatalerror("DSP16: op %u doesn't take two cycles to run from cache\n", op >> 11);
+ }
+ break;
+
+ case phase::PREFETCH:
+ break;
+
+ default:
+ throw emu_fatalerror("DSP16: inappropriate phase for cache execution\n");
+ }
+
+ if (phase::PREFETCH == m_phase)
+ {
+ m_phase = phase::OP1;
+ overlap_rom_data_read();
+ m_st_pcbase = (m_cache_pcbase & 0xf000U) | ((m_cache_pcbase + m_cache_ptr) & 0x0fffU);
+ }
+ else if (phase::OP1 == m_phase)
+ {
+ if (last_instruction)
+ {
+ // overlapped fetch of next instruction from ROM
+ m_cache_mode = cache::NONE;
+ m_cache[m_cache_ptr = 0] = m_direct->read_word(m_xaau_pc);
+ m_st_pcbase = m_xaau_pc;
+ }
+ else
+ {
+ if (at_limit)
+ {
+ // loop to first cached instruction
+ m_cache_ptr = 1U;
+ --m_cache_iterations;
+ }
+ else
+ {
+ // move to next cached instruction
+ m_cache_ptr = (m_cache_ptr + 1) & 0x0fU;
+ }
+ overlap_rom_data_read();
+ m_st_pcbase = (m_cache_pcbase & 0xf000U) | ((m_cache_pcbase + m_cache_ptr) & 0x0fffU);
+ }
}
}
-//-------------------------------------------------
-// disassemble - call the disassembly
-// helper function
-//-------------------------------------------------
+inline void dsp16_device_base::overlap_rom_data_read()
+{
+ assert(cache::EXECUTE == m_cache_mode);
+ assert(phase::OP1 == m_phase);
+ u16 const op(m_cache[m_cache_ptr]);
+ switch (op >> 11)
+ {
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i]
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ m_rom_data = m_direct->read_word(m_xaau_pt);
+ break;
+ }
+}
-util::disasm_interface *dsp16_device::create_disassembler()
+inline void dsp16_device_base::yaau_short_immediate_load(u16 op)
{
- return new dsp16a_disassembler;
+ u16 const r((op >> 9) & 0x0007U);
+ u16 const m(op & 0x01ff);
+ switch (r)
+ {
+ case 0x0: // j
+ m_yaau_j = m | ((m & m_yaau_sign) ? ~m_yaau_mask : 0);
+ break;
+ case 0x1: // k
+ m_yaau_k = m | ((m & m_yaau_sign) ? ~m_yaau_mask : 0);
+ break;
+ case 0x2: // rb
+ m_yaau_rb = m;
+ break;
+ case 0x3: // re
+ m_yaau_re = m;
+ break;
+ case 0x4: // r0
+ case 0x5: // r1
+ case 0x6: // r2
+ case 0x7: // r3
+ m_yaau_r[r & 0x0003U] = m;
+ break;
+ }
}
+inline s16 dsp16_device_base::yaau_read(u16 op)
+{
+ s16 const result(m_spaces[AS_DATA]->read_word(op_yaau_r(op)));
+ yaau_postmodify_r(op);
+ return result;
+}
-/***************************************************************************
- MEMORY ACCESSORS
-***************************************************************************/
+inline void dsp16_device_base::yaau_write(u16 op, s16 value)
+{
+ m_spaces[AS_DATA]->write_word(op_yaau_r(op), value);
+ yaau_postmodify_r(op);
+}
-inline uint32_t dsp16_device::data_read(const uint16_t& addr)
+void dsp16_device_base::yaau_write_z(u16 op)
{
- return m_data->read_word(addr);
+ u16 &r(op_yaau_r(op));
+ m_spaces[AS_DATA]->write_word(r, m_dau_temp);
+ switch (op & 0x0003U)
+ {
+ case 0x0: // *rNzp
+ // TODO: does virtual shift register addressing apply here?
+ if (m_yaau_re && (m_yaau_re == r))
+ r = m_yaau_rb;
+ else
+ ++r;
+ break;
+ case 0x1: // *rNpz
+ break;
+ case 0x2: // *rNm2
+ r += 2;
+ break;
+ case 0x3: // *rNjk;
+ r += m_yaau_k;
+ break;
+ }
+ r &= m_yaau_mask;
}
-inline void dsp16_device::data_write(const uint16_t& addr, const uint16_t& data)
+inline u64 dsp16_device_base::dau_f1(u16 op)
{
- m_data->write_word(addr, data & 0xffff);
+ s64 const &s(op_dau_as(op));
+ s64 d(0);
+ switch (op_f1(op))
+ {
+ case 0x0: // aD = p ; p = x*y
+ d = get_dau_p_aligned();
+ m_dau_p = m_dau_x * (m_dau_y >> 16);
+ break;
+ case 0x1: // aD = aS + p ; p = x*y
+ d = s + get_dau_p_aligned();
+ m_dau_p = m_dau_x * (m_dau_y >> 16);
+ break;
+ case 0x2: // p = x*y
+ m_dau_p = m_dau_x * (m_dau_y >> 16);
+ return op_dau_ad(op);
+ case 0x3: // aD = aS - p ; p = x*y
+ d = s - get_dau_p_aligned();
+ m_dau_p = m_dau_x * (m_dau_y >> 16);
+ break;
+ case 0x4: // aD = p
+ d = get_dau_p_aligned();
+ break;
+ case 0x5: // aD = aS + p
+ d = s + get_dau_p_aligned();
+ break;
+ case 0x6: // NOP
+ return op_dau_ad(op);
+ case 0x7: // aD = aS - p
+ d = s - get_dau_p_aligned();
+ break;
+ case 0x8: // aD = aS | y
+ d = s | m_dau_y;
+ break;
+ case 0x9: // aD = aS ^ y
+ d = s ^ m_dau_y;
+ break;
+ case 0xa: // aS & y
+ set_dau_psw_flags(s & m_dau_y);
+ return op_dau_ad(op);
+ case 0xb: // aS - y
+ set_dau_psw_flags(s - m_dau_y);
+ return op_dau_ad(op);
+ case 0xc: // aD = y
+ d = m_dau_y;
+ break;
+ case 0xd: // aD = aS + y
+ d = s + m_dau_y;
+ break;
+ case 0xe: // aD = aS & y
+ d = s & m_dau_y;
+ break;
+ case 0xf: // aD = aS - y
+ d = s - m_dau_y;
+ break;
+ }
+ return set_dau_psw_flags(d);
}
-inline uint32_t dsp16_device::opcode_read(const uint8_t pcOffset)
+inline u64 dsp16_device_base::dau_f2(u16 op)
{
- const uint16_t readPC = m_pc + pcOffset;
- return m_direct->read_dword(readPC);
+ s64 const &s(op_dau_as(op));
+ s64 d(0);
+ switch (op_f2(op))
+ {
+ case 0x0: // aD = aS >> 1
+ d = s >> 1;
+ break;
+ case 0x1: // aD = aS << 1
+ d = s << 1;
+ break;
+ case 0x2: // aD = aS >> 4
+ d = s >> 4;
+ break;
+ case 0x3: // aD = aS << 4
+ d = s << 4;
+ break;
+ case 0x4: // aD = aS >> 8
+ d = s >> 8;
+ break;
+ case 0x5: // aD = aS << 8
+ d = d << 8;
+ break;
+ case 0x6: // aD = aS >> 16
+ d = s >> 16;
+ break;
+ case 0x7: // aD = aS << 16
+ d = s << 16;
+ break;
+ case 0x8: // aD = p
+ d = get_dau_p_aligned();
+ break;
+ case 0x9: // aDh = aSh + 1
+ d = s64(s32(u32(u64(s)) & ~((u32(1) << 16) - 1))) + (s32(1) << 16);
+ if (BIT(m_dau_auc, op_s(op) + 4))
+ d |= op_dau_ad(op) & ((s64(1) << 16) - 1);
+ break;
+ case 0xa: // Reserved
+ throw emu_fatalerror("DSP16: reserved F2 value %01X (PC = %04X)\n", op_f2(op), m_st_pcbase);
+ case 0xb: // aD = rnd(aS)
+ // FIXME: behaviour is not clear
+ // p 3-13: "Round upper 20 bits of accumulator."
+ // p 3-14: "The contents of the source accumulator, aS, are rounded to 16 bits, and the sign-extended result is placed in aD[35 - 16] with zeroes in aD[15 - 0]."
+ // It presumably rounds to nearest, but does it yield a 16-bit or 20-bit result, and what does it do about overflow?
+ d = (s + ((0 > s) ? -(s16(1) << 15) : (s16(1) << 15))) & ~((u64(1) << 16) - 1);
+ break;
+ case 0xc: // aD = y
+ d = m_dau_y;
+ break;
+ case 0xd: // aD = aS + 1
+ d = s + 1;
+ break;
+ case 0xe: // aD = aS
+ d = s;
+ break;
+ case 0xf: // aD = -aS
+ // FIXME: does this detect negation of largest negative number as overflow?
+ d = -s;
+ break;
+ }
+ return set_dau_psw_flags(d);
}
+/***********************************************************************
+ inline helpers
+***********************************************************************/
-/***************************************************************************
- CORE EXECUTION LOOP
-***************************************************************************/
+inline bool dsp16_device_base::op_interruptible(u16 op)
+{
+ switch (op >> 11)
+ {
+ case 0x02: // R = M
+ case 0x03:
+ case 0x04: // F1 ; Y = a1[l]
+ case 0x05: // F1 ; Z : aT[l]
+ case 0x06: // F1 ; Y
+ case 0x07: // F1 ; aT[l] = Y
+ case 0x08: // aT = R
+ case 0x09: // R = a0
+ case 0x0a: // R = N
+ case 0x0b: // R = a1
+ case 0x0c: // Y = R
+ case 0x0d: // Z : R
+ case 0x0f: // R = Y
+ case 0x12: // ifc CON F2
+ case 0x13: // if CON F2
+ case 0x14: // F1 ; Y = y[l]
+ case 0x15: // F1 ; Z : y[l]
+ case 0x16: // F1 ; x = Y
+ case 0x17: // F1 ; y[l] = Y
+ case 0x19: // y = a0 ; x = *pt++[i]
+ case 0x1b: // y = a1 ; x = *pt++[i]
+ case 0x1c: // F1 ; Y = a0[l]
+ case 0x1d: // F1 ; Z : y ; x = *pt++[i]
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i]
+ return true;
+ case 0x00: // goto JA
+ case 0x01:
+ case 0x0e: // do K { instre1...instrNI } # redo K
+ case 0x10: // call JA
+ case 0x11:
+ case 0x18: // goto B
+ case 0x1a: // if CON # icall
+ case 0x1e: // Reserved
+ default:
+ return false;
+ };
+}
+
+inline bool dsp16_device_base::check_predicate()
+{
+ bool const result(FLAGS_PRED_FALSE != (m_flags & FLAGS_PRED_MASK));
+ set_predicate(FLAGS_PRED_NONE);
+ return result;
+}
+
+inline u16 &dsp16_device_base::set_xaau_pc_offset(u16 offset)
+{
+ m_xaau_pc = (m_xaau_pc & 0xf000U) | (offset & 0x0fffU);
+ if (m_iack_out)
+ m_xaau_pi = m_xaau_pc;
+ return m_xaau_pc;
+}
+
+inline s16 dsp16_device_base::get_r(u16 op)
+{
+ switch (op_r(op))
+ {
+ case 0x00: // r0 (u)
+ case 0x01: // r1 (u)
+ case 0x02: // r2 (u)
+ case 0x03: // r3 (u)
+ return m_yaau_r[op_r(op)];
+ case 0x04: // j (s)
+ return m_yaau_j;
+ case 0x05: // k (s)
+ return m_yaau_k;
+ case 0x06: // rb (u)
+ return m_yaau_rb;
+ case 0x07: // re (u)
+ return m_yaau_re;
+ case 0x08: // pt
+ return m_xaau_pt;
+ case 0x09: // pr
+ return m_xaau_pr;
+ case 0x0a: // pi
+ return m_xaau_pi;
+ case 0x0b: // i (s)
+ return m_xaau_i;
+ case 0x10: // x
+ return m_dau_x;
+ case 0x11: // y
+ return u16(u32(m_dau_y >> 16));
+ case 0x12: // yl
+ return u16(u32(m_dau_y));
+ break;
+ case 0x13: // auc (u)
+ return m_dau_auc;
+ case 0x14: // psw
+ return m_dau_psw = (m_dau_psw & 0xfe10U) | (u16(u64(m_dau_a[0]) >> 32) & 0x000fU) | (u16(u64(m_dau_a[1]) >> 27) & 0x01e0U);
+ case 0x15: // c0 (s)
+ case 0x16: // c1 (s)
+ case 0x17: // c2 (s)
+ return m_dau_c[op_r(op) - 0x15];
+ case 0x18: // sioc
+ return m_sio_sioc;
+ case 0x19: // srta
+ logerror("DSP16: unimplemented get SRTA\n");
+ return 0;
+ case 0x1a: // sdx
+ logerror("DSP16: unimplemented get SDX\n");
+ return 0;
+ case 0x1b: // tdms
+ logerror("DSP16: unimplemented get TDMS\n");
+ return 0;
+ case 0x1c: // pioc
+ return m_pio_pioc;
+ case 0x1d: // pdx0
+ case 0x1e: // pdx1
+ return pio_pdx_read(BIT(op_r(op), 1));
+ default:
+ throw emu_fatalerror("DSP16: invalid R value %02X (PC = %04X)\n", op_r(op), m_st_pcbase);
+ }
+}
+
+inline void dsp16_device_base::set_r(u16 op, s16 value)
+{
+ switch (op_r(op))
+ {
+ case 0x00: // r0 (u)
+ case 0x01: // r1 (u)
+ case 0x02: // r2 (u)
+ case 0x03: // r3 (u)
+ m_yaau_r[op_r(op)] = value & m_yaau_mask;
+ break;
+ case 0x04: // j (s)
+ m_yaau_j = (value & m_yaau_mask) | ((value & m_yaau_sign) ? ~m_yaau_mask : 0);
+ break;
+ case 0x05: // k (s)
+ m_yaau_k = (value & m_yaau_mask) | ((value & m_yaau_sign) ? ~m_yaau_mask : 0);
+ break;
+ case 0x06: // rb (u)
+ m_yaau_rb = value & m_yaau_mask;
+ break;
+ case 0x07: // re (u)
+ m_yaau_re = value & m_yaau_mask;
+ break;
+ case 0x08: // pt
+ m_xaau_pt = value;
+ break;
+ case 0x09: // pr
+ m_xaau_pr = value;
+ break;
+ case 0x0a: // pi
+ // FIXME: reset PRNG
+ if (!m_iack_out)
+ m_xaau_pi = value;
+ break;
+ case 0x0b: // i (s)
+ m_xaau_i = (value & XAAU_I_MASK) | ((value & XAAU_I_SIGN) ? XAAU_I_EXT : 0);
+ break;
+ case 0x10: // x
+ m_dau_x = value;
+ break;
+ case 0x11: // y
+ m_dau_y = (u32(u16(value)) << 16) | u32(BIT(m_dau_auc, 6) ? u16(u32(m_dau_y)) : u16(0));
+ break;
+ case 0x12: // yl
+ m_dau_y = (m_dau_y & 0xffff'0000) | u32(u16(value));
+ break;
+ case 0x13: // auc (u)
+ m_dau_auc = u8(value & 0x007f);
+ break;
+ case 0x14: // psw
+ m_dau_psw = value;
+ m_dau_a[0] = u64(u32(m_dau_a[0])) | (u64(value & 0x000fU) << 32) | (BIT(value, 3) ? DAU_A_EXT : 0U);
+ m_dau_a[1] = u64(u32(m_dau_a[1])) | (u64(value & 0x01e0U) << 27) | (BIT(value, 8) ? DAU_A_EXT : 0U);
+ break;
+ case 0x15: // c0 (s)
+ case 0x16: // c1 (s)
+ case 0x17: // c2 (s)
+ m_dau_c[op_r(op) - 0x15] = u8(u16(value));
+ break;
+ case 0x18: // sioc
+ sio_sioc_write(value);
+ break;
+ case 0x19: // srta
+ logerror("DSP16: unimplemented SRTA = %04X\n", value);
+ break;
+ case 0x1a: // sdx
+ LOGSIO("DSP16: write SDX = %04X%s (PC = %04X)\n", value, pio_obe_status() ? "" : " - overrun", m_st_pcbase);
+ if (pio_obe_status())
+ LOGINT("DSP16 clear OBE flag (PC = %04X)\n", m_st_pcbase);
+ m_sio_obuf = value;
+ m_pio_pioc &= ~(u16(1) << 3);
+ break;
+ case 0x1b: // tdms
+ logerror("DSP16: unimplemented TDMS = %04X\n", value);
+ break;
+ case 0x1c: // pioc
+ pio_pioc_write(value);
+ break;
+ case 0x1d: // pdx0
+ case 0x1e: // pdx1
+ pio_pdx_write(BIT(op_r(op), 1), value);
+ break;
+ default:
+ throw emu_fatalerror("DSP16: invalid R value %02X (PC = %04X)\n", op_r(op), m_st_pcbase);
+ }
+}
-//-------------------------------------------------
-// execute_min_cycles - return minimum number of
-// cycles it takes for one instruction to execute
-//-------------------------------------------------
+inline void dsp16_device_base::yaau_postmodify_r(u16 op)
+{
+ u16 &r(op_yaau_r(op));
+ switch (op & 0x0003U)
+ {
+ case 0x0: // *rN
+ break;
+ case 0x1: // *rN++
+ if (m_yaau_re && (m_yaau_re == r))
+ r = m_yaau_rb;
+ else
+ ++r;
+ break;
+ case 0x2: // *rN--
+ --r;
+ break;
+ case 0x3: // *rN++j
+ r += m_yaau_j;
+ break;
+ }
+ r &= m_yaau_mask;
+}
-uint32_t dsp16_device::execute_min_cycles() const
+inline void dsp16_device_base::set_dau_y(u16 op, s16 value)
{
- return 1;
+ if (op_x(op))
+ {
+ bool const clear(!BIT(m_dau_psw, 6));
+ m_dau_y = (u32(u16(value)) << 16) | u32(clear ? u16(0) : u16(u32(m_dau_y)));
+ }
+ else
+ {
+ m_dau_y = (m_dau_y & ~((s32(1) << 16) - 1)) | u32(u16(value));
+ }
}
+inline void dsp16_device_base::set_dau_at(u16 op, s16 value)
+{
+ s64 &at(op_dau_at(op));
+ if (op_x(op))
+ {
+ bool const clear(!BIT(m_dau_psw, 4 + op_d(~op)));
+ at = s32((u32(u16(value)) << 16) | u32(clear ? u16(0) : u16(u64(at))));
+ }
+ else
+ {
+ at = (at & ~((s64(1) << 16) - 1)) | u64(u16(value));
+ }
+}
-//-------------------------------------------------
-// execute_max_cycles - return maximum number of
-// cycles it takes for one instruction to execute
-//-------------------------------------------------
+inline u64 dsp16_device_base::set_dau_psw_flags(s64 d)
+{
+ m_dau_psw &= 0x0fffU;
+ bool const negative(d & DAU_A_SIGN);
+ if (negative)
+ m_dau_psw |= 0x8000U;
+ if (!(d & DAU_A_MASK))
+ m_dau_psw |= 0x4000U;
+ if ((d >> 36) != (negative ? -1 : 0))
+ m_dau_psw |= 0x2000U;
+ if (((d >> 32) & ((1 << 4) - 1)) != (BIT(d, 31) ? 15 : 0))
+ m_dau_psw |= 0x1000U;
+ if (negative)
+ return d | DAU_A_EXT;
+ else
+ return d & DAU_A_MASK;
+}
-uint32_t dsp16_device::execute_max_cycles() const
+inline u64 dsp16_device_base::get_dau_p_aligned() const
{
- return 1;
+ // TODO: manual is contradictory
+ // p 2-10: "Bits 1 and 2 of the accumulator are not changed by the load of the accumulator with the data in p, since 00 is added to or copied into these accumulator bits as indicated in Figure 2-8."
+ // I'm reading this as copying p to aD clears the low two bits, but adding it leaves them unchanged.
+ switch (dau_auc_align())
+ {
+ case 0x0:
+ return m_dau_p;
+ case 0x1:
+ return m_dau_p >> 2;
+ case 0x2:
+ return u64(m_dau_p) << 2;
+ case 0x3:
+ default:
+ throw emu_fatalerror("DSP16: reserved ALIGN value %01X (PC = %04X)\n", dau_auc_align(), m_st_pcbase);
+ }
}
+inline bool dsp16_device_base::op_dau_con(u16 op)
+{
+ bool result;
+ u16 const con(op_con(op));
+ switch (con >> 1)
+ {
+ case 0x0: // mi/pl
+ result = dau_psw_lmi();
+ break;
+ case 0x1: // eq/ne
+ result = dau_psw_leq();
+ break;
+ case 0x2: // lvs/lvc
+ result = dau_psw_llv();
+ break;
+ case 0x3: // mvs/mvc
+ result = dau_psw_lmv();
+ break;
+ case 0x4: // heads/tails
+ throw emu_fatalerror("DSP16: unimplemented CON value %02X (PC = %04X)\n", con, m_st_pcbase);
+ case 0x5: // c0ge/c0lt
+ case 0x6: // c1ge/c1lt
+ result = m_dau_c[(con >> 1) - 0x5]++ >= 0;
+ break;
+ case 0x7: // true/false
+ result = true;
+ break;
+ case 0x8: // gt/le
+ result = !dau_psw_lmi() && !dau_psw_leq();
+ break;
+ default:
+ throw emu_fatalerror("DSP16: reserved CON value %02X (PC = %04X)\n", con, m_st_pcbase);
+ }
+ return BIT(con, 0) ? !result : result;
+}
-//-------------------------------------------------
-// execute_input_lines - return the number of
-// input/interrupt lines
-//-------------------------------------------------
+/***********************************************************************
+ serial I/O
+***********************************************************************/
-uint32_t dsp16_device::execute_input_lines() const
+void dsp16_device_base::sio_sioc_write(u16 value)
{
- return 1;
+ static constexpr unsigned DIVIDERS[4] = { 4U, 12U, 16U, 20U };
+ value &= 0x03ffU;
+ LOGSIO(
+ "DSP16: write SIOC = %03X: "
+ "LD %cCK/n->%cCK/n, CLK CKI/%u->CKI/%u, %cSB->%cSB first, "
+ "OLD %s->%s, ILD %s->%s, OCK %s->%s, ICK %s->%s, OLEN %u->%u, ILEN %u->%u "
+ "(PC = %04X)\n",
+ value,
+ sio_ld_ock() ? 'O' : 'I', BIT(value, 9) ? 'O' : 'I',
+ DIVIDERS[(m_sio_sioc >> 7) & 0x0003U], DIVIDERS[(value >> 7) & 0x0003U],
+ sio_msb_first() ? 'M' : 'L', BIT(value, 6) ? 'M' : 'L',
+ sio_old_active() ? "active" : "passive", BIT(value, 5) ? "active" : "passive",
+ sio_ild_active() ? "active" : "passive", BIT(value, 4) ? "active" : "passive",
+ sio_ock_active() ? "active" : "passive", BIT(value, 3) ? "active" : "passive",
+ sio_ick_active() ? "active" : "passive", BIT(value, 2) ? "active" : "passive",
+ sio_olen(), BIT(value, 1) ? 8U : 16U,
+ sio_ilen(), BIT(value, 0) ? 8U : 16U,
+ m_st_pcbase);
+
+ //bool const ock_change(BIT(value ^ m_sio_sioc, 5));
+ //bool const ild_change(BIT(value ^ m_sio_sioc, 4));
+ bool const ock_change(BIT(value ^ m_sio_sioc, 3));
+ bool const ick_change(BIT(value ^ m_sio_sioc, 2));
+ m_sio_sioc = value;
+
+ // we're using treating high-impedance and high as the same thing
+ if (!m_sio_clk)
+ {
+ if (ick_change)
+ m_ick_cb(sio_ick_active() ? 0 : 1);
+ if (ock_change)
+ m_ock_cb(sio_ock_active() ? 0 : 1);
+ }
}
+inline void dsp16_device_base::sio_ick_active_edge()
+{
+ // check for start of transaction
+ bool const ild(sio_ild_active() ? !m_sio_ld : (CLEAR_LINE != m_ild_in));
+ if (ASSERT_LINE != m_ild_in)
+ m_ild_in = CLEAR_LINE;
+ if (ild)
+ {
+ // FIXME: implement enough to put something here
+ m_sio_flags |= SIO_FLAGS_ILD;
+ }
+ else
+ {
+ m_sio_flags &= ~SIO_FLAGS_ILD;
+ }
+
+ // update internal LD divider if it's being driven by ICK
+ if (sio_ld_ick())
+ sio_step_ld_div();
+}
-void dsp16_device::execute_set_input(int inputnum, int state)
+inline void dsp16_device_base::sio_ock_active_edge()
{
- // Only has one external IRQ line
+ // check for load opportunity
+ bool const old(sio_old_active() ? !m_sio_ld : (CLEAR_LINE != m_old_in));
+ if (ASSERT_LINE != m_old_in)
+ m_old_in = CLEAR_LINE;
+ if (old)
+ {
+ if ((SIO_FLAGS_NONE == (m_sio_flags & SIO_FLAGS_OLD)) && !m_sio_ofsr && !pio_obe_status())
+ {
+ bool const eight_bit(8U == sio_olen());
+ LOGSIO(
+ "DSP16: load OSR = %04X & %04X %cSB first (PC = %04X)\n",
+ m_sio_obuf, !eight_bit ? 0xffffU : sio_msb_first() ? 0xff00U : 0x00ffU, sio_msb_first() ? 'M' : 'L', m_st_pcbase);
+ LOGINT("DSP16: set OBE flag (PC = %04X)\n", m_st_pcbase);
+
+ m_sio_osr = sio_msb_first() ? bitswap<16>(m_sio_obuf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) : m_sio_obuf;
+ m_sio_ofsr = 0xffffU;
+ if (eight_bit)
+ {
+ m_sio_osr |= 0xff00U;
+ m_sio_ofsr >>= 8;
+ }
+
+ m_pio_pioc |= u16(1) << 3;
+ }
+ m_sio_flags |= SIO_FLAGS_OLD;
+ }
+ else
+ {
+ m_sio_flags &= ~SIO_FLAGS_OLD;
+ }
+
+ // shift out serial data
+ if (BIT(m_sio_osr, 0) != m_do_out)
+ m_do_cb(m_do_out = BIT(m_sio_osr, 0));
+ if (BIT(~m_sio_ofsr, 0) != m_ose_out)
+ {
+ LOGSIO("DSP16: OSE %u->%u (PC = %04X)\n", m_ose_out, BIT(~m_sio_ofsr, 0), m_st_pcbase);
+ m_ose_cb(m_ose_out = BIT(~m_sio_ofsr, 0));
+ }
+ m_sio_osr = (m_sio_osr >> 1) | 0x8000U;
+ m_sio_ofsr >>= 1;
+
+ // update internal LD divider if it's being driven by OCK
+ if (sio_ld_ock())
+ sio_step_ld_div();
}
+inline void dsp16_device_base::sio_step_ld_div()
+{
+ if (m_sio_ld_div)
+ {
+ --m_sio_ld_div;
+ }
+ else
+ {
+ m_sio_ld = m_sio_ld ? 0U : 1U;
+ m_sio_ld_div = (16 / 2) - 1;
+ if (sio_ild_active())
+ m_ild_cb(m_sio_ld);
+ if (sio_old_active())
+ m_old_cb(m_sio_ld);
+ }
+}
-void dsp16_device::execute_run()
+/***********************************************************************
+ parallel I/O
+***********************************************************************/
+
+void dsp16_device_base::pio_pioc_write(u16 value)
{
- // HACK TO MAKE CPU DO NOTHING.
- // REMOVE IF DEVELOPING CPU CORE.
- m_icount = 0;
- return;
+ LOGPIO(
+ "DSP16: write PIOC = %04X: "
+ "STROBE %uT->%uT, PODS %s->%s, PIDS %s->%s, S/C %u->%u, "
+ "IBF %s->%s, OBE %s->%s, PIDS %s->%s, PODS %s->%s, INT %s->%s "
+ "(PC = %04X)\n",
+ value,
+ pio_strobe(), ((value >> 13) & 0x0003U) + 1,
+ pio_pods_active() ? "active" : "passive", BIT(value, 12) ? "active" : "passive",
+ pio_pids_active() ? "active" : "passive", BIT(value, 11) ? "active" : "passive",
+ BIT(m_pio_pioc, 10), BIT(value, 10),
+ pio_ibf_enable() ? "en" : "dis", BIT(value, 9) ? "en" : "dis",
+ pio_obe_enable() ? "en" : "dis", BIT(value, 8) ? "en" : "dis",
+ pio_pids_enable() ? "en" : "dis", BIT(value, 7) ? "en" : "dis",
+ pio_pods_enable() ? "en" : "dis", BIT(value, 6) ? "en" : "dis",
+ pio_int_enable() ? "en" : "dis", BIT(value, 5) ? "en" : "dis",
+ m_st_pcbase);
- do
+ m_pio_pioc = (m_pio_pioc & 0x801fU) | (value & 0x7fe0U);
+ m_int_enable[1] = (value >> 5) & 0x001fU;
+ if (!pio_pids_active())
{
- // debugging
- m_ppc = m_pc; // copy PC to previous PC
- debugger_instruction_hook(this, m_pc);
+ m_pio_pids_cnt = 0U;
+ if (!m_pids_out)
+ m_pids_cb(m_pids_out = 1U); // actually high-impedance
+ }
+ if (!pio_pods_active())
+ {
+ m_pio_pods_cnt = 0U;
+ if (!m_pods_out)
+ {
+ m_pods_cb(m_pods_out = 1U); // actually high-impedance
+ m_pdb_w_cb(machine().dummy_space(), m_psel_out, 0xffffU, 0x0000U);
+ }
+ }
+}
- // instruction fetch & execute
- uint8_t cycles;
- uint8_t pcAdvance;
- const uint16_t op = opcode_read();
- execute_one(op, cycles, pcAdvance);
+u16 dsp16_device_base::pio_pdx_read(u16 sel)
+{
+ bool const active(pio_pids_active());
+ LOGPIO("DSP16: read PDX%u = %04X %s (PC = %04X)\n", sel, m_pio_pdx_in, active ? "active" : "passive", m_st_pcbase);
+ if (pio_pids_status())
+ LOGINT("DSP16: clear PIDS flag (PC = %04X)\n", m_st_pcbase);
+ m_pio_pioc &= ~(u16(1) << 2);
- // step
- m_pc += pcAdvance;
- m_icount -= cycles;
+ if (sel != m_psel_out)
+ {
+ LOGPIO("DSP16: PSEL %u->%u (PC = %04X)\n", m_psel_out, sel, m_st_pcbase);
+ m_psel_cb(m_psel_out = sel);
+ }
- // The 16 bit PI "shadow" register gets set to PC on each instruction except
- // when an interrupt service routine is active (TODO: Interrupt check) (page 2-4)
- m_pi = m_pc;
+ if (active)
+ {
+ if (m_pio_pids_cnt)
+ {
+ assert(!m_pids_out);
+ logerror("DSP16: PDX%u active read while PIDS still asserted (PC = %04X)\n", sel, m_st_pcbase);
+ }
+ else
+ {
+ assert(m_pids_out);
+ m_pids_cb(m_pids_out = 0U);
+ }
+ m_pio_pids_cnt = pio_strobe() + 1; // decremented this cycle
+ }
- } while (m_icount > 0);
+ return m_pio_pdx_in;
}
-#include "dsp16ops.hxx"
+void dsp16_device_base::pio_pdx_write(u16 sel, u16 value)
+{
+ bool const active(pio_pods_active());
+ LOGPIO("DSP16: write PDX%u = %04X %s (PC = %04X)\n", sel, value, active ? "active" : "passive", m_st_pcbase);
+ if (pio_pods_status())
+ LOGINT("DSP16: clear PODS flag (PC = %04X)\n", m_st_pcbase);
+ m_pio_pioc &= ~(u16(1) << 1);
+ m_pio_pdx_out = value;
+
+ if (sel != m_psel_out)
+ {
+ LOGPIO("DSP16: PSEL %u->%u (PC = %04X)\n", m_psel_out, sel, m_st_pcbase);
+ m_psel_cb(m_psel_out = sel);
+ }
+
+ if (active)
+ {
+ if (m_pio_pods_cnt)
+ {
+ assert(!m_pods_out);
+ logerror("DSP16: PDX%u active write while PODS still asserted (PC = %04X)\n", sel, m_st_pcbase);
+ }
+ else
+ {
+ assert(m_pods_out);
+ m_pods_cb(m_pods_out = 0U);
+ m_pdb_w_cb(machine().dummy_space(), sel, value, 0xffffU);
+ }
+ m_pio_pods_cnt = pio_strobe() + 1; // decremented this cycle
+ }
+}
+
+
+/***************************************************************************
+ DSP16 SPECIALISATION
+***************************************************************************/
+
+dsp16_device::dsp16_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : dsp16_device_base(
+ mconfig, DSP16, tag, owner, clock,
+ 9,
+ address_map_constructor(FUNC(dsp16_device::data_map), this))
+ , m_rom(*this, DEVICE_SELF, 0x0800)
+{
+}
+
+void dsp16_device::external_memory_enable(address_space &space, bool enable)
+{
+ // manual implies the DSP16 doesn't support enabling both internal and external ROM at the same time (page 2-2)
+ // this assumes internal ROM is mirrored above 2KiB, but actual hardware behaviour is unknown
+ space.unmap_read(0x0000, 0xffff);
+ if (enable)
+ space.install_read_handler(0x0000, 0xffff, read16_delegate(FUNC(dsp16_device::external_memory_r<0x0000>), this));
+ else
+ space.install_rom(0x0000, 0x07ff, 0xf800, &m_rom[0]);
+}
+
+void dsp16_device::data_map(address_map &map)
+{
+ map.global_mask(0x01ff);
+ map.unmap_value_high();
+ map(0x0000, 0x01ff).ram();
+}
+
+
+/***************************************************************************
+ DSP16A SPECIALISATION
+***************************************************************************/
+
+dsp16a_device::dsp16a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : dsp16_device_base(
+ mconfig, DSP16A, tag, owner, clock,
+ 16,
+ address_map_constructor(FUNC(dsp16a_device::data_map), this))
+ , m_rom(*this, DEVICE_SELF, 0x1000)
+{
+}
+
+void dsp16a_device::external_memory_enable(address_space &space, bool enable)
+{
+ space.unmap_read(0x0000, 0xffff);
+ if (enable)
+ {
+ space.install_read_handler(0x0000, 0xffff, read16_delegate(FUNC(dsp16a_device::external_memory_r<0x0000>), this));
+ }
+ else
+ {
+ space.install_rom(0x0000, 0x0fff, &m_rom[0]);
+ space.install_read_handler(0x1000, 0xffff, read16_delegate(FUNC(dsp16a_device::external_memory_r<0x1000>), this));
+ }
+}
+
+void dsp16a_device::data_map(address_map &map)
+{
+ map.global_mask(0x07ff);
+ map.unmap_value_high();
+ map(0x0000, 0x07ff).ram();
+}
diff --git a/src/devices/cpu/dsp16/dsp16.h b/src/devices/cpu/dsp16/dsp16.h
index 2dcf6892833..22295ceea6b 100644
--- a/src/devices/cpu/dsp16/dsp16.h
+++ b/src/devices/cpu/dsp16/dsp16.h
@@ -1,10 +1,8 @@
// license:BSD-3-Clause
-// copyright-holders:Andrew Gardner
+// copyright-holders:Vas Crabb
/***************************************************************************
- dsp16.h
-
- WE|AT&T DSP16 series emulator.
+ WE|AT&T DSP16 series emulator
***************************************************************************/
@@ -13,172 +11,443 @@
#pragma once
+#include <utility>
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-// ======================> dsp16_device
+#define MCFG_DSP16_EXM(exm) \
+ downcast<dsp16_device_base &>(*device).exm_w(exm);
-class dsp16_device : public cpu_device
-{
-public:
- // construction/destruction
- dsp16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+#define MCFG_DSP16_EXM_HIGH() \
+ downcast<dsp16_device_base &>(*device).exm_w(1);
- // public interfaces
+#define MCFG_DSP16_EXM_LOW() \
+ downcast<dsp16_device_base &>(*device).exm_w(0);
-protected:
- enum
- {
- DSP16_I, // ROM Address Arithmetic Unit (XAAU)
- DSP16_PC,
- DSP16_PT,
- DSP16_PR,
- DSP16_PI,
- DSP16_J, // RAM Address Arithmetic Unit (YAAU)
- DSP16_K,
- DSP16_RB,
- DSP16_RE,
- DSP16_R0,
- DSP16_R1,
- DSP16_R2,
- DSP16_R3,
- DSP16_X, // Data Arithmetic Unit (DAU)
- DSP16_Y,
- DSP16_P,
- DSP16_A0,
- DSP16_A1,
- DSP16_AUC,
- DSP16_PSW,
- DSP16_C0,
- DSP16_C1,
- DSP16_C2,
- DSP16_SIOC,
- DSP16_SRTA,
- DSP16_SDX,
- DSP16_PIOC,
- DSP16_PDX0,
- DSP16_PDX1
- };
+#define MCFG_DSP16_IACK_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_iack_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_ICK_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_ick_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_ILD_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_ild_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_DO_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_do_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_OCK_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_ock_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_OLD_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_old_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_OSE_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_ose_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_PIO_R_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_pio_r_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_PIO_W_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_pio_w_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_PDB_W_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_pdb_w_cb(DEVCB_##obj);
+#define MCFG_DSP16_PSEL_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_psel_cb(DEVCB_##obj);
- // device-level overrides
+#define MCFG_DSP16_PIDS_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_pids_cb(DEVCB_##obj);
+
+#define MCFG_DSP16_PODS_CB(obj) \
+ downcast<dsp16_device_base &>(*device).set_pods_cb(DEVCB_##obj);
+
+
+class dsp16_device_base : public cpu_device
+{
+public:
+ DECLARE_WRITE_LINE_MEMBER(exm_w);
+
+ // interrupt output callbacks
+ template <typename Obj> devcb_base *set_iack_cb(Obj &&cb) { return &m_iack_cb.set_callback(std::forward<Obj>(cb)); }
+
+ // serial output callbacks
+ template <typename Obj> devcb_base *set_ick_cb(Obj &&cb) { return &m_ick_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_ild_cb(Obj &&cb) { return &m_ild_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_do_cb(Obj &&cb) { return &m_do_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_ock_cb(Obj &&cb) { return &m_ock_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_old_cb(Obj &&cb) { return &m_old_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_ose_cb(Obj &&cb) { return &m_ose_cb.set_callback(std::forward<Obj>(cb)); }
+
+ // high-level active parallel I/O callbacks
+ template <typename Obj> devcb_base *set_pio_r_cb(Obj &&cb) { return &m_pio_r_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_pio_w_cb(Obj &&cb) { return &m_pio_w_cb.set_callback(std::forward<Obj>(cb)); }
+
+ // low-level parallel I/O callbacks
+ template <typename Obj> devcb_base *set_pdb_w_cb(Obj &&cb) { return &m_pdb_w_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_psel_cb(Obj &&cb) { return &m_psel_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_pids_cb(Obj &&cb) { return &m_pids_cb.set_callback(std::forward<Obj>(cb)); }
+ template <typename Obj> devcb_base *set_pods_cb(Obj &&cb) { return &m_pods_cb.set_callback(std::forward<Obj>(cb)); }
+
+ // interrupt outputs
+ DECLARE_READ_LINE_MEMBER(iack_r) { return m_iack_out; }
+
+ // serial outputs
+ DECLARE_READ_LINE_MEMBER(ick_r) { return sio_ick_active() ? m_sio_clk : 1; }
+ DECLARE_READ_LINE_MEMBER(ild_r) { return sio_ild_active() ? m_sio_ld : 1; }
+ DECLARE_READ_LINE_MEMBER(do_r) { return m_do_out; }
+ DECLARE_READ_LINE_MEMBER(ock_r) { return sio_ock_active() ? m_sio_clk : 1; }
+ DECLARE_READ_LINE_MEMBER(old_r) { return sio_old_active() ? m_sio_ld : 1; }
+ DECLARE_READ_LINE_MEMBER(ose_r) { return m_ose_out; }
+
+ // high-level passive parallel I/O handlers
+ DECLARE_READ16_MEMBER(pio_r);
+ DECLARE_WRITE16_MEMBER(pio_w);
+
+ // parallel I/O outputs
+ DECLARE_READ_LINE_MEMBER(psel_r) { return m_psel_out; }
+ DECLARE_READ_LINE_MEMBER(pids_r) { return m_pids_out; }
+ DECLARE_READ_LINE_MEMBER(pods_r) { return m_pods_out; }
+
+protected:
+ // construction/destruction
+ dsp16_device_base(
+ machine_config const &mconfig,
+ device_type type,
+ char const *tag,
+ device_t *owner,
+ u32 clock,
+ u8 yaau_bits,
+ address_map_constructor &&data_map);
+
+ // device_t implementation
+ virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
- // device_execute_interface overrides
- virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const override { return (clocks + 2 - 1) / 2; } // internal /2 divider
- virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const override { return (cycles * 2); } // internal /2 divider
- virtual uint32_t execute_min_cycles() const override;
- virtual uint32_t execute_max_cycles() const override;
- virtual uint32_t execute_input_lines() const override;
+ // device_execute_interface implementation
+ virtual u64 execute_clocks_to_cycles(u64 clocks) const override { return (clocks + 2 - 1) >> 1; }
+ virtual u64 execute_cycles_to_clocks(u64 cycles) const override { return cycles << 1; }
+ virtual u32 execute_input_lines() const override { return 5U; }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
- // device_memory_interface overrides
+ // device_memory_interface implementation
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;
+ // device_state_interface implementation
+ virtual void state_import(device_state_entry const &entry) override;
+ virtual void state_export(device_state_entry const &entry) override;
- // device_disasm_interface overrides
+ // device_disasm_interface implementation
virtual util::disasm_interface *create_disassembler() override;
- // address spaces
- const address_space_config m_program_config;
- const address_space_config m_data_config;
-
- // CPU registers
- // ROM Address Arithmetic Unit (XAAU) (page 2-4)
- uint16_t m_i; // 12 bits
- uint16_t m_pc;
- uint16_t m_pt;
- uint16_t m_pr;
- uint16_t m_pi;
-
- // RAM Address Arithmetic Unit (YAAU) (page 2-6)
- uint16_t m_j; // Signed
- uint16_t m_k; // Signed
- uint16_t m_rb;
- uint16_t m_re;
- uint16_t m_r0;
- uint16_t m_r1;
- uint16_t m_r2;
- uint16_t m_r3;
-
- // Data Arithmetic Unit (DAU) (page 2-6)
- uint16_t m_x;
- uint32_t m_y;
- uint32_t m_p;
- uint64_t m_a0; // 36 bits
- uint64_t m_a1; // 36 bits
- uint8_t m_auc; // 6 bits
- uint16_t m_psw;
- uint8_t m_c0;
- uint8_t m_c1;
- uint8_t m_c2;
-
- // Serial and parallel interfaces (TODO: More here (page 2-13))
- uint16_t m_sioc;
- uint16_t m_srta;
- uint16_t m_sdx;
- uint16_t m_pioc;
- uint16_t m_pdx0; // pdx0 & pdx1 refer to the same physical register (page 6-1)
- uint16_t m_pdx1; // but we keep them separate for logic's sake.
-
- // internal stuff
- uint16_t m_ppc;
-
- // This CPU core handles the cache as more of a loop than 15 separate memory elements.
- // It's a bit of a hack, but it's easier this way (for now).
- uint16_t m_cacheStart;
- uint16_t m_cacheEnd;
- uint16_t m_cacheRedoNextPC;
- uint16_t m_cacheIterations;
- static const uint16_t CACHE_INVALID = 0xffff;
-
- // memory access
- inline uint32_t data_read(const uint16_t& addr);
- inline void data_write(const uint16_t& addr, const uint16_t& data);
- inline uint32_t opcode_read(const uint8_t pcOffset=0);
-
- // address spaces
- address_space* m_program;
- address_space* m_data;
- direct_read_data<-1> *m_direct;
-
- // other internal states
- int m_icount;
-
- // operations
- void execute_one(const uint16_t& op, uint8_t& cycles, uint8_t& pcAdvance);
-
- // table decoders
- void* registerFromRImmediateField(const uint8_t& R);
- void* registerFromRTable(const uint8_t& R);
- uint16_t* registerFromYFieldUpper(const uint8_t& Y);
-
- // execution
- void executeF1Field(const uint8_t& F1, const uint8_t& D, const uint8_t& S);
- void executeYFieldPost(const uint8_t& Y);
- void executeZFieldPartOne(const uint8_t& Z, uint16_t* rN);
- void executeZFieldPartTwo(const uint8_t& Z, uint16_t* rN);
-
- // helpers
- void* addressYL();
- void writeRegister(void* reg, const uint16_t& value);
- bool conditionTest(const uint8_t& CON);
-
- // flags
- bool lmi();
- bool leq();
- bool llv();
- bool lmv();
+ // for specialisations to override
+ virtual void external_memory_enable(address_space &space, bool enable) = 0;
+
+ template <offs_t Base> DECLARE_READ16_MEMBER(external_memory_r);
+
+private:
+ // state registration indices
+ enum
+ {
+ DSP16_PT = 1, DSP16_PR, DSP16_PI, DSP16_I,
+ DSP16_R0, DSP16_R1, DSP16_R2, DSP16_R3, DSP16_RB, DSP16_RE, DSP16_J, DSP16_K,
+ DSP16_X, DSP16_Y, DSP16_P, DSP16_A0, DSP16_A1, DSP16_C0, DSP16_C1, DSP16_C2, DSP16_AUC, DSP16_PSW,
+ DSP16_YH, DSP16_A0H, DSP16_A1H, DSP16_YL, DSP16_A0L, DSP16_A1L
+ };
+
+ // masks for registers that aren't power-of-two sizes
+ enum : s16
+ {
+ XAAU_I_SIGN = s16(1) << (12 - 1),
+ XAAU_I_MASK = (s16(1) << 12) - 1,
+ XAAU_I_EXT = ~XAAU_I_MASK
+ };
+ enum : s64
+ {
+ DAU_A_SIGN = s64(1) << (36 - 1),
+ DAU_A_MASK = (s64(1) << 36) - 1,
+ DAU_A_EXT = ~DAU_A_MASK
+ };
+
+ // execution state
+ enum class cache : u8 { NONE, LOAD, EXECUTE };
+ enum class phase : u8 { PURGE, OP1, OP2, PREFETCH };
+ enum flags : u8
+ {
+ FLAGS_PRED_NONE = 0x00U,
+ FLAGS_PRED_TRUE = 0x01U,
+ FLAGS_PRED_FALSE = 0x02U,
+ FLAGS_PRED_MASK = 0x03U,
+
+ FLAGS_IACK_NONE = 0x00U,
+ FLAGS_IACK_SET = 0x04U,
+ FLAGS_IACK_CLEAR = 0x08U,
+ FLAGS_IACK_MASK = 0x0cU,
+
+ FLAGS_NONE = FLAGS_PRED_NONE | FLAGS_IACK_NONE
+ };
+ friend constexpr flags operator~(flags);
+ friend constexpr flags operator&(flags, flags);
+ friend constexpr flags operator|(flags, flags);
+ friend flags &operator&=(flags &, flags);
+ friend flags &operator|=(flags &, flags);
+
+ // serial I/O state
+ enum sio_flags : u8
+ {
+ SIO_FLAGS_NONE = 0x00U,
+ SIO_FLAGS_ILD = 0x01U,
+ SIO_FLAGS_OLD = 0x02U
+ };
+ friend constexpr sio_flags operator~(sio_flags);
+ friend constexpr sio_flags operator&(sio_flags, sio_flags);
+ friend constexpr sio_flags operator|(sio_flags, sio_flags);
+ friend sio_flags &operator&=(sio_flags &, sio_flags);
+ friend sio_flags &operator|=(sio_flags &, sio_flags);
+
+ // internal address maps
+ void program_map(address_map &map);
+
+ // instruction execution
+ void execute_one_rom();
+ void execute_one_cache();
+ void overlap_rom_data_read();
+ void yaau_short_immediate_load(u16 op);
+ s16 yaau_read(u16 op);
+ void yaau_write(u16 op, s16 value);
+ void yaau_write_z(u16 op);
+ u64 dau_f1(u16 op);
+ u64 dau_f2(u16 op);
+
+ // inline helpers
+ static bool op_interruptible(u16 op);
+ bool check_predicate();
+ flags &set_predicate(flags predicate) { return m_flags = (m_flags & ~FLAGS_PRED_MASK) | (predicate & FLAGS_PRED_MASK); }
+ flags &set_iack(flags iack) { return m_flags = (m_flags & ~FLAGS_IACK_MASK) | (iack & FLAGS_IACK_MASK); }
+ u16 &set_xaau_pc_offset(u16 offset);
+ void xaau_increment_pt(s16 increment) { m_xaau_pt = (m_xaau_pt & XAAU_I_EXT) | ((m_xaau_pt + increment) & XAAU_I_MASK); }
+ s16 get_r(u16 op);
+ void set_r(u16 op, s16 value);
+ void yaau_postmodify_r(u16 op);
+ void set_dau_y(u16 op, s16 value);
+ void set_dau_at(u16 op, s16 value);
+ u64 set_dau_psw_flags(s64 d);
+ u64 get_dau_p_aligned() const;
+ bool op_dau_con(u16 op);
+
+ // flag accessors
+ u16 dau_auc_align() const { return m_dau_auc & 0x0003U; }
+ bool dau_psw_lmi() const { return bool(BIT(m_dau_psw, 15)); }
+ bool dau_psw_leq() const { return bool(BIT(m_dau_psw, 14)); }
+ bool dau_psw_llv() const { return bool(BIT(m_dau_psw, 13)); }
+ bool dau_psw_lmv() const { return bool(BIT(m_dau_psw, 12)); }
+
+ // opcode field handling
+ static constexpr u16 op_ja(u16 op) { return op & 0x0fffU; }
+ static constexpr u16 op_b(u16 op) { return (op >> 8) & 0x0007U; }
+ static constexpr u16 op_d(u16 op) { return BIT(op, 10); }
+ static constexpr u16 op_s(u16 op) { return BIT(op, 9); }
+ static constexpr u16 op_f1(u16 op) { return (op >> 5) & 0x000fU; }
+ static constexpr u16 op_f2(u16 op) { return (op >> 5) & 0x000fU; }
+ static constexpr u16 op_r(u16 op) { return (op >> 4) & 0x003fU; }
+ static constexpr u16 op_x(u16 op) { return BIT(op, 4); }
+ static constexpr u16 op_con(u16 op) { return op & 0x001fU; }
+ static constexpr u16 op_ni(u16 op) { return (op >> 7) & 0x000fU; }
+ static constexpr u16 op_k(u16 op) { return op & 0x007fU; }
+ s16 op_xaau_increment(u16 op) const { return op_x(op) ? m_xaau_i : 1; }
+ u16 &op_yaau_r(u16 op) { return m_yaau_r[(op >> 2) & 0x0003U]; }
+ s64 &op_dau_as(u16 op) { return m_dau_a[op_s(op)]; }
+ s64 &op_dau_ad(u16 op) { return m_dau_a[op_d(op)]; }
+ s64 &op_dau_at(u16 op) { return m_dau_a[op_d(~op)]; }
+
+ // serial I/O
+ bool sio_ld_ick() const { return !BIT(m_sio_sioc, 9); }
+ bool sio_ld_ock() const { return bool(BIT(m_sio_sioc, 9)); }
+ bool sio_lsb_first() const { return !BIT(m_sio_sioc, 6); }
+ bool sio_msb_first() const { return bool(BIT(m_sio_sioc, 6)); }
+ bool sio_old_active() const { return bool(BIT(m_sio_sioc, 5)); }
+ bool sio_ild_active() const { return bool(BIT(m_sio_sioc, 4)); }
+ bool sio_ock_active() const { return bool(BIT(m_sio_sioc, 3)); }
+ bool sio_ick_active() const { return bool(BIT(m_sio_sioc, 2)); }
+ unsigned sio_olen() const { return BIT(m_sio_sioc, 1) ? 8U : 16U; }
+ unsigned sio_ilen() const { return BIT(m_sio_sioc, 0) ? 8U : 16U; }
+ void sio_sioc_write(u16 value);
+ void sio_ick_active_edge();
+ void sio_ock_active_edge();
+ void sio_step_ld_div();
+
+ // parallel I/O
+ u16 pio_strobe() const { return ((m_pio_pioc >> 13) & 0x0003U) + 1; }
+ bool pio_pods_active() const { return bool(BIT(m_pio_pioc, 12)); }
+ bool pio_pids_active() const { return bool(BIT(m_pio_pioc, 11)); }
+ bool pio_sc_mode() const { return bool(BIT(m_pio_pioc, 10)); }
+ bool pio_ibf_enable() const { return bool(BIT(m_pio_pioc, 9)); }
+ bool pio_obe_enable() const { return bool(BIT(m_pio_pioc, 8)); }
+ bool pio_pids_enable() const { return bool(BIT(m_pio_pioc, 7)); }
+ bool pio_pods_enable() const { return bool(BIT(m_pio_pioc, 6)); }
+ bool pio_int_enable() const { return bool(BIT(m_pio_pioc, 5)); }
+ bool pio_ibf_status() const { return bool(BIT(m_pio_pioc, 4)); }
+ bool pio_obe_status() const { return bool(BIT(m_pio_pioc, 3)); }
+ bool pio_pids_status() const { return bool(BIT(m_pio_pioc, 2)); }
+ bool pio_pods_status() const { return bool(BIT(m_pio_pioc, 1)); }
+ bool pio_int_status() const { return bool(BIT(m_pio_pioc, 0)); }
+ void pio_pioc_write(u16 value);
+ u16 pio_pdx_read(u16 sel);
+ void pio_pdx_write(u16 sel, u16 value);
+
+ // interrupt callbacks
+ devcb_write_line m_iack_cb;
+
+ // serial output callbacks
+ devcb_write_line m_ick_cb, m_ild_cb;
+ devcb_write_line m_do_cb, m_ock_cb, m_old_cb, m_ose_cb;
+
+ // parallel I/O callbacks
+ devcb_read16 m_pio_r_cb;
+ devcb_write16 m_pio_w_cb;
+ devcb_write16 m_pdb_w_cb;
+ devcb_write_line m_psel_cb, m_pids_cb, m_pods_cb;
+
+ // configuration
+ address_space_config const m_space_config[3];
+ u16 const m_yaau_mask;
+ u16 const m_yaau_sign;
+
+ // memory system access
+ address_space *m_spaces[3];
+ direct_read_data<-1> *m_direct;
+
+ // execution state
+ int m_icount;
+ cache m_cache_mode;
+ phase m_phase;
+ u8 m_int_enable[2];
+ flags m_flags;
+ u8 m_cache_ptr, m_cache_limit, m_cache_iterations;
+ u16 m_cache[16];
+ u16 m_rom_data;
+
+ // line states
+ u8 m_exm_in; // internal ROM disabled when low
+ u8 m_int_in; // external interrupt request
+ u8 m_iack_out; // asserted (low) while servicing interrupt
+
+ // serial I/O line states
+ u8 m_ick_in; // data input clock - sampled on rising edge
+ u8 m_ild_in; // data input clock - sampled on rising edge
+ u8 m_do_out; // serial data output - changes on rising edges of OCK
+ u8 m_ock_in; // data output clock - output changes on rising edge
+ u8 m_old_in; // falling edge indicates beginning of output word
+ u8 m_ose_out; // indicates the end of a serial transmission
+
+ // parallel I/O line states
+ u8 m_psel_out; // last accessed parallel I/O data register
+ u8 m_pids_out; // parallel input data strobe (sampled on rising edge)
+ u8 m_pods_out; // parallel output data strobe
+
+ // XAAU - ROM Address Arithmetic Unit
+ u16 m_xaau_pc; // 16 bits unsigned
+ u16 m_xaau_pt; // 16 bits unsigned
+ u16 m_xaau_pr; // 16 bits unsigned
+ u16 m_xaau_pi; // 16 bits unsigned
+ s16 m_xaau_i; // 12 bits signed
+
+ // YAAU - RAM Address Arithmetic Unit
+ u16 m_yaau_r[4]; // 9/16 bits unsigned
+ u16 m_yaau_rb; // 9/16 bits unsigned
+ u16 m_yaau_re; // 9/16 bits unsigned
+ s16 m_yaau_j; // 9/16 bits signed
+ s16 m_yaau_k; // 9/16 bits signed
+
+ // DAU - Data Arithmetic Unit
+ s16 m_dau_x; // 16 bits signed
+ s32 m_dau_y; // 32 bits signed
+ s32 m_dau_p; // 32 bits signed
+ s64 m_dau_a[2]; // 36 bits signed
+ s8 m_dau_c[3]; // 8 bits signed
+ u8 m_dau_auc; // 7 bits unsigned
+ u16 m_dau_psw; // 16 bits
+ s16 m_dau_temp; // 16 bits
+
+ // SIO - Serial I/O
+ u16 m_sio_sioc; // 10 bits
+ u16 m_sio_obuf; // 16 bits
+ u16 m_sio_osr; // 16 bits
+ u16 m_sio_ofsr; // 16 bits
+ u8 m_sio_clk;
+ u8 m_sio_clk_div;
+ u8 m_sio_ld;
+ u8 m_sio_ld_div;
+ sio_flags m_sio_flags;
+
+ // PIO - Parallel I/O
+ u16 m_pio_pioc; // 16 bits
+ u16 m_pio_pdx_in; // 16 bits
+ u16 m_pio_pdx_out; // 16 bits
+ u8 m_pio_pids_cnt;
+ u8 m_pio_pods_cnt;
+
+ // fake registers for the debugger
+ u16 m_cache_pcbase;
+ u16 m_st_pcbase;
+ s16 m_st_yh, m_st_ah[2];
+ u16 m_st_yl, m_st_al[2];
+};
+
+
+class dsp16_device : public dsp16_device_base
+{
+public:
+ // construction/destruction
+ dsp16_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+protected:
+ // dsp16_device_base implementation
+ virtual void external_memory_enable(address_space &space, bool enable) override;
+
+ // internal address maps
+ void data_map(address_map &map);
+
+private:
+ required_region_ptr<u16> m_rom;
};
-// device type definition
+class dsp16a_device : public dsp16_device_base
+{
+public:
+ // construction/destruction
+ dsp16a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+protected:
+ // dsp16_device_base implementation
+ virtual void external_memory_enable(address_space &space, bool enable) override;
+
+ // internal address maps
+ void data_map(address_map &map);
+
+private:
+ required_region_ptr<u16> m_rom;
+};
+
+
+enum
+{
+ DSP16_INT_LINE = INPUT_LINE_IRQ0,
+ DSP16_ICK_LINE,
+ DSP16_ILD_LINE,
+ DSP16_OCK_LINE,
+ DSP16_OLD_LINE
+};
+
+
+DECLARE_ENUM_BITWISE_OPERATORS(dsp16_device_base::flags)
+DECLARE_ENUM_BITWISE_OPERATORS(dsp16_device_base::sio_flags)
+
+
DECLARE_DEVICE_TYPE(DSP16, dsp16_device)
+DECLARE_DEVICE_TYPE(DSP16A, dsp16a_device)
#endif // MAME_CPU_DSP16_DSP16_H
diff --git a/src/devices/cpu/dsp16/dsp16ops.hxx b/src/devices/cpu/dsp16/dsp16ops.hxx
deleted file mode 100644
index ab54a577fef..00000000000
--- a/src/devices/cpu/dsp16/dsp16ops.hxx
+++ /dev/null
@@ -1,937 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Andrew Gardner
-#include "dsp16.h"
-
-#define DSP_LINE(__DSP_DOCLINE__) printf("0x%04x - %d (%s)\n", m_pc, __LINE__, __DSP_DOCLINE__);
-
-// TODO:
-// * AUC has a CLR field for writing to A0 & A1 + sign extension + psw + zero lower bits
-// implement as a clean function (page 2-7)
-// * Implement saturation overflow (SAT on AUC) (page 2-8)
-// * Implement p alignment (ALIGN on AUC) (page 2-9)
-// * When a register is used as a memory pointer. its value is compared with re. If its value is
-// equal to the contents of re and the postincrement is +1, then the value in rb is copied into
-// the register after the memory access is complete. See Section 4.2.3.
-// * CPU flags go to the PSW & conditionTest() works on that (Page 3-4)
-// * Some instructions are not interruptible.
-//
-
-
-// NOTES:
-// When y is used in an assembly-language instruction, the DSPI6/DSPI6A device will read
-// or write the high half (bits 16-31) of the y register (page 2-7)
-
-// The YL register is the lower half of the 32 bit Y register
-void* dsp16_device::addressYL()
-{
- return (void*)(((uint8_t*)&m_y) + 2);
-}
-
-
-// Flag getters
-bool dsp16_device::lmi()
-{
- return m_psw & 0x8000;
-}
-
-bool dsp16_device::leq()
-{
- return m_psw & 0x4000;
-}
-
-bool dsp16_device::llv()
-{
- return m_psw & 0x2000;
-}
-
-bool dsp16_device::lmv()
-{
- return m_psw & 0x1000;
-}
-
-
-void dsp16_device::writeRegister(void* reg, const uint16_t &value)
-{
- // Make sure you're not attempting to write somewhere this function doesn't support.
- if (reg == &m_p || reg == &m_a0 || reg == &m_a1)
- {
- logerror("dsp16::writeRegister called on invalid register at PC 0x%04x.\n", m_pc);
- return;
- }
-
- if (reg == &m_auc || reg == &m_c0 || reg == &m_c1 || reg == &m_c2)
- {
- // 8 bit registers
- *(uint8_t*)reg = value & 0x00ff;
- }
- else if (reg == &m_psw)
- {
- // Writes to the a0 & a1 guard bits too
- m_a0 &= 0x0ffffffffU;
- m_a0 |= u64(m_psw & 0x000fU) << 32;
- m_a1 &= 0x0ffffffffU;
- m_a1 |= u64(m_psw & 0x01e0U) << 27;
- m_psw = value;
- }
- else if (reg == &m_i)
- {
- // 12 bit register
- m_i = value & 0x0fff;
- }
- else if (reg == &m_y)
- {
- // Y register
- // TODO - Automatic clearing of yl may be selected (according to the CLR field of the auc register) (page 2-7)
- m_y = (value << 16) | (m_y & 0x0000ffff);
- }
- else if (reg == addressYL())
- {
- // Yl register (Writes to yl do not change the data in the high half of y)
- m_y = value | (m_y & 0xffff0000);
- }
- else
- {
- // Everything else
- *(uint16_t*)reg = value;
- }
-}
-
-
-bool dsp16_device::conditionTest(const uint8_t& CON)
-{
- switch (CON)
- {
- case 0x00: return lmi(); // mi (negative result)
- case 0x01: return !lmi(); // pl (positive result)
- case 0x02: return leq(); // eq (result == 0)
- case 0x03: return !leq(); // ne (result != 0)
- case 0x04: return llv(); // lvs (logical overflow set)
- case 0x05: return !llv(); // lvc (logical overflow clear)
- case 0x06: return lmv(); // mvs (math. overflow set)
- case 0x07: return !lmv(); // mvc (math. overflow clear)
- case 0x08: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // heads (random bit set)
- case 0x09: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // tails (random bit clear)
- case 0x0a: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0ge (counter0 >= 0)*
- case 0x0b: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0lt (counter0 < 0)*
- case 0x0c: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1ge (counter1 >= 0)*
- case 0x0d: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1lt (counter1 < 0)*
- case 0x0e: return true; // true (always)
- case 0x0f: return false; // false (never)
- case 0x10: return (!lmi() && !leq()); // gt (result > 0)
- case 0x11: return (lmi() || leq()); // le (result <= 0)
- default: logerror("Unrecognized condition at PC=0x%04x\n", m_pc); break;
- }
-
- // Testing each of these conditions (*) increments the respective counter being tested (page 3-5)
-
- return false;
-}
-
-
-void* dsp16_device::registerFromRImmediateField(const uint8_t& R)
-{
- switch (R)
- {
- case 0x00: return (void*)&m_j;
- case 0x01: return (void*)&m_k;
- case 0x02: return (void*)&m_rb;
- case 0x03: return (void*)&m_re;
- case 0x04: return (void*)&m_r0;
- case 0x05: return (void*)&m_r1;
- case 0x06: return (void*)&m_r2;
- case 0x07: return (void*)&m_r3;
-
- default: return nullptr;
- }
- return nullptr;
-}
-
-
-void* dsp16_device::registerFromRTable(const uint8_t &R)
-{
- switch (R)
- {
- case 0x00: return (void*)&m_r0;
- case 0x01: return (void*)&m_r1;
- case 0x02: return (void*)&m_r2;
- case 0x03: return (void*)&m_r3;
- case 0x04: return (void*)&m_j;
- case 0x05: return (void*)&m_k;
- case 0x06: return (void*)&m_rb;
- case 0x07: return (void*)&m_re;
- case 0x08: return (void*)&m_pt;
- case 0x09: return (void*)&m_pr;
- case 0x0a: return (void*)&m_pi;
- case 0x0b: return (void*)&m_i;
-
- case 0x10: return (void*)&m_x;
- case 0x11: return (void*)&m_y;
- case 0x12: return (void*)addressYL();
- case 0x13: return (void*)&m_auc; // zero extended
- case 0x14: return (void*)&m_psw;
- case 0x15: return (void*)&m_c0; // sign extended
- case 0x16: return (void*)&m_c1; // sign extended
- case 0x17: return (void*)&m_c2; // sign extended
- case 0x18: return (void*)&m_sioc;
- case 0x19: return (void*)&m_srta;
- case 0x1a: return (void*)&m_sdx;
- case 0x1b: logerror("dsp16::registerFromRTable tdms requested 0x%04x.\n", m_pc); break;
- case 0x1c: return (void*)&m_pioc;
- case 0x1d: return (void*)&m_pdx0;
- case 0x1e: return (void*)&m_pdx1;
-
- default: return nullptr;
- }
- return nullptr;
-}
-
-
-void dsp16_device::executeF1Field(const uint8_t& F1, const uint8_t& D, const uint8_t& S)
-{
- // TODO: I'm pretty sure we need to feed X into these as well - Double check
-
- // Note these instructions read right-to-left, so act accordingly (page 3-6)
- // y & p are sign extended (page 3-9)
- // implementation details (page 3-9)
-
- // Where is are the results going?
- uint64_t* destinationReg = nullptr;
- switch (D)
- {
- case 0x00: destinationReg = &m_a0; break;
- case 0x01: destinationReg = &m_a1; break;
- default: break;
- }
-
- // Which source is being used?
- uint64_t* sourceReg = nullptr;
- switch (S)
- {
- case 0x00: sourceReg = &m_a0; break;
- case 0x01: sourceReg = &m_a1; break;
- default: break;
- }
-
-
- // We must compute into an intermediate variable to compute flags on
- uint64_t result = 0;
- bool justATest = false;
-
- switch (F1)
- {
- case 0x00:
- {
- // Ad = p p = x*y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x01:
- {
- // Ad = aS+p p = x*y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x02:
- {
- // p = x*y
- // TODO: What happens to the flags in this operation?
- const int16_t y = (m_y & 0xffff0000) >> 16;
- m_p = (int32_t)((int16_t)m_x * y);
- justATest = true;
- break;
- }
- case 0x03:
- {
- // Ad = aS-p p = x*y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x04:
- {
- // Ad = p
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x05:
- {
- // Ad = aS+p
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x06:
- {
- // nop
- justATest = true;
- break;
- }
- case 0x07:
- {
- // Ad = aS-p
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x08:
- {
- // Ad = aS|y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x09:
- {
- // Ad = aS^y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x0a:
- {
- // aS&y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- justATest = true;
- break;
- }
- case 0x0b:
- {
- // aS-y
- int64_t aS = *sourceReg;
- if (aS & 0x800000000U)
- aS |= 0xfffffff000000000U;
-
- int64_t y = (m_y & 0xffff0000) >> 16;
- if (y & 0x8000)
- y |= 0xffffffffffff0000U;
-
- result = aS-y;
- justATest = true;
- break;
- }
- case 0x0c:
- {
- // Ad = y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x0d:
- {
- // Ad = aS+y
- int64_t aS = *sourceReg;
- if (aS & 0x800000000U)
- aS |= 0xfffffff000000000U;
-
- int64_t y = (m_y & 0xffff0000) >> 16;
- if (y & 0x8000)
- y |= 0xffffffffffff0000U;
-
- result = aS+y;
- break;
- }
- case 0x0e:
- {
- // Ad = aS&y
- printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
- break;
- }
- case 0x0f:
- {
- // Ad = aS-y
- int64_t aS = *sourceReg;
- if (aS & 0x800000000U)
- aS |= 0xfffffff000000000U;
-
- int64_t y = (m_y & 0xffff0000) >> 16;
- if (y & 0x8000)
- y |= 0xffffffffffff0000U;
-
- result = aS-y;
- break;
- }
- }
-
- // CPU Flags (page 3-4)
- // LMI (logical minus)
- if (result & 0x800000000U)
- m_psw |= 0x8000;
- else
- m_psw &= (~0x8000);
-
- // LEQ (logical equal)
- if (result == 0x000000000U)
- m_psw |= 0x4000;
- else
- m_psw &= (~0x4000);
-
- // LLV (logical overflow)
- // TODO
-
- // LMV (mathematical overflow)
- if ((result & 0xf00000000U) != 0xf00000000U &&
- (result & 0xf00000000U) != 0x000000000U)
- m_psw |= 0x1000;
- else
- m_psw &= (~0x1000);
-
- // If it was a real operation, make sure the data goes where it should
- if (!justATest)
- *destinationReg = (uint64_t)result & 0x0000000fffffffffU;
-}
-
-
-uint16_t* dsp16_device::registerFromYFieldUpper(const uint8_t& Y)
-{
- uint16_t* destinationReg = nullptr;
- const uint8_t N = (Y & 0x0c) >> 2;
- switch (N)
- {
- case 0x00: destinationReg = &m_r0; break;
- case 0x01: destinationReg = &m_r1; break;
- case 0x02: destinationReg = &m_r2; break;
- case 0x03: destinationReg = &m_r3; break;
- default: break;
- }
- return destinationReg;
-}
-
-
-void dsp16_device::executeYFieldPost(const uint8_t& Y)
-{
- uint16_t* opReg = registerFromYFieldUpper(Y);
-
- const uint8_t lower = Y & 0x03;
- switch (lower)
- {
- case 0x00: /* nop */ break;
- case 0x01: (*opReg)++; break;
- case 0x02: (*opReg)--; break;
- case 0x03: (*opReg) += m_j; break; // TODO: J is signed
- }
-}
-
-
-void dsp16_device::executeZFieldPartOne(const uint8_t& Z, uint16_t* rN)
-{
- const uint8_t lower = Z & 0x03;
- switch (lower)
- {
- case 0x00: /* nop */ break;
- case 0x01: (*rN)++; break;
- case 0x02: (*rN)--; break;
- case 0x03: (*rN) += m_j; break; // TODO: J is signed
- }
-}
-
-
-void dsp16_device::executeZFieldPartTwo(const uint8_t& Z, uint16_t* rN)
-{
- const uint8_t lower = Z & 0x03;
- switch (lower)
- {
- case 0x00: (*rN)++; break;
- case 0x01: /* nop */ break;
- case 0x02: (*rN) += 2; break;
- case 0x03: (*rN) += m_k; break; // TODO: K is signed
- }
-}
-
-
-void dsp16_device::execute_one(const uint16_t& op, uint8_t& cycles, uint8_t& pcAdvance)
-{
- cycles = 1;
- pcAdvance = 0;
-
-// NOTE: pages 3-5 through 3-19 are good english descriptions of what's up
-
- const uint8_t opcode = (op >> 11) & 0x1f;
- switch(opcode)
- {
- // Format 1: Multiply/ALU Read/Write Group
- case 0x06:
- {
- DSP_LINE("3-38")
- // F1, Y : (page 3-38)
- const uint8_t Y = (op & 0x000f);
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- executeYFieldPost(Y);
- cycles = 1;
- pcAdvance = 1;
- break;
- }
- case 0x04: case 0x1c:
- {
- DSP_LINE("3-40")
- // F1 Y=a0[1] | F1 Y=a1[1] : (page 3-40)
- const uint8_t Y = (op & 0x000f);
- //const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- uint16_t* destinationReg = registerFromYFieldUpper(Y);
- // (page 3-18)
- uint16_t aRegValue = 0x0000;
- if (op & 0xc000)
- {
- aRegValue = (m_a0 & 0x0ffff0000U) >> 16;
- }
- else
- {
- aRegValue = (m_a1 & 0x0ffff0000U) >> 16;
- }
- data_write(*destinationReg, aRegValue);
- executeYFieldPost(Y);
- executeF1Field(F1, D, S);
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x16:
- {
- DSP_LINE("3-42")
- // F1, x = Y : (page 3-42)
- const uint8_t Y = (op & 0x000f);
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* sourceReg = registerFromYFieldUpper(Y);
- writeRegister(&m_x, data_read(*sourceReg));
- executeYFieldPost(Y);
- cycles = 1;
- pcAdvance = 1;
- break;
- }
- case 0x17:
- {
- DSP_LINE("3-44")
- // F1, y[l] = Y : (page 3-44)
- const uint8_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* sourceReg = registerFromYFieldUpper(Y);
- uint16_t sourceValue = data_read(*sourceReg);
- switch (X)
- {
- case 0x00: writeRegister(addressYL(), sourceValue); break;
- case 0x01: writeRegister(&m_y, sourceValue); break;
- default: break;
- }
- executeYFieldPost(Y);
- cycles = 1;
- pcAdvance = 1;
- break;
- }
- case 0x1f:
- {
- DSP_LINE("3-46")
- // F1, y = Y, x = *pt++[i] : (page 3-46)
- const uint8_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* sourceRegR = registerFromYFieldUpper(Y);
- writeRegister(&m_y, data_read(*sourceRegR));
- executeYFieldPost(Y);
- writeRegister(&m_x, data_read(m_pt));
- switch (X)
- {
- case 0x00: m_pt++; break;
- case 0x01: m_pt += m_i; break;
- }
- cycles = 2; // TODO: 1 if cached
- pcAdvance = 1;
- break;
- }
- case 0x19: case 0x1b:
- {
- DSP_LINE("3-48")
- // F1, y = a0|1, x = *pt++[i] : (page 3-48)
- const uint8_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- bool useA1 = (opcode == 0x1b);
- if (Y != 0x00) printf("Unknown opcode @ PC=0x%04x", m_pc);
- m_y = (useA1) ? (m_a1 & 0xffffffff) : (m_a0 & 0xffffffff); // TODO: What happens to Ax when it goes 32 bit (pc=3f & pc=47)?
- executeF1Field(F1, D, S);
- writeRegister(&m_x, data_read(m_pt)); // TODO: EXM Pin & internal/external ROM? Research.
- switch (X)
- {
- case 0x00: m_pt++; break;
- case 0x01: m_pt += m_i; break;
- }
- cycles = 2; // TODO: 1 if cached
- pcAdvance = 1;
- break;
- }
- case 0x14:
- {
- DSP_LINE("3-53")
- // F1, Y = y[l] : (page 3-53)
- const uint8_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* destinationReg = registerFromYFieldUpper(Y);
- uint16_t yRegValue = 0x0000;
- switch (X)
- {
- case 0x00: yRegValue = (m_y & 0x0000ffff); break;
- case 0x01: yRegValue = (m_y & 0xffff0000) >> 16; break;
- default: break;
- }
- data_write(*destinationReg, yRegValue);
- executeYFieldPost(Y);
- cycles = 2;
- pcAdvance = 1;
- break;
- }
-
- // Format 1a: Multiply/ALU Read/Write Group (TODO: Figure out major typo in docs on p3-51)
- case 0x07:
- {
- DSP_LINE("3-50")
- // F1, At[1] = Y : (page 3-50)
- // TODO: What does the X field do here, exactly?
- const uint8_t Y = (op & 0x000f);
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t aT = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, !aT, S);
- uint64_t* destinationReg = nullptr;
- switch(aT)
- {
- case 0: destinationReg = &m_a1; break;
- case 1: destinationReg = &m_a0; break;
- default: break;
- }
- uint16_t sourceAddress = *(registerFromYFieldUpper(Y));
- int64_t sourceValueSigned = (int16_t)data_read(sourceAddress);
- *destinationReg = sourceValueSigned & 0xffffffffffU;
- executeYFieldPost(Y);
- cycles = 1;
- pcAdvance = 1;
- break;
- }
-
- // Format 2: Multiply/ALU Read/Write Group
- case 0x15:
- {
- DSP_LINE("3-54")
- // F1, Z : y[l] : (page 3-54)
- const uint8_t Z = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t temp = 0x0000;
- uint16_t* rN = registerFromYFieldUpper(Z);
- switch (X)
- {
- case 0x00:
- temp = m_y & 0x0000ffff;
- m_y &= 0xffff0000;
- m_y |= data_read(*rN);
- executeZFieldPartOne(Z, rN);
- data_write(*rN, temp);
- executeZFieldPartTwo(Z, rN);
- break;
- case 0x01:
- temp = (m_y & 0xffff0000) >> 16;
- m_y &= 0x0000ffff;
- m_y |= (data_read(*rN) << 16);
- executeZFieldPartOne(Z, rN);
- data_write(*rN, temp);
- executeZFieldPartTwo(Z, rN);
- break;
- }
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x1d:
- {
- DSP_LINE("?")
- // F1, Z : y, x=*pt++[i]
- //const uint8_t Z = (op & 0x000f);
- //const uint8_t X = (op & 0x0010) >> 4;
- //const uint8_t S = (op & 0x0200) >> 9;
- //const uint8_t D = (op & 0x0400) >> 10;
- //const uint8_t F1 = (op & 0x01e0) >> 5;
- break;
- }
-
- // Format 2a: Multiply/ALU Read/Write Group
- case 0x05:
- {
- DSP_LINE("?")
- // F1, Z : aT[1]
- //const uint8_t Z = (op & 0x000f);
- //const uint8_t X = (op & 0x0010) >> 4;
- //const uint8_t S = (op & 0x0200) >> 9;
- //const uint8_t aT = (op & 0x0400) >> 10;
- //const uint8_t F1 = (op & 0x01e0) >> 5;
- break;
- }
-
- // Format 3: Special Functions
- case 0x12:
- case 0x13:
- {
- DSP_LINE("3-36")
- // if|ifc CON F2 (page 3-36)
- const uint8_t CON = (op & 0x001f);
- //const uint8_t S = (op & 0x0200) >> 9;
- //const uint8_t D = (op & 0x0400) >> 10;
- //const uint8_t F2 = (op & 0x01e0) >> 5;
- bool conditionFulfilled = conditionTest(CON);
- if (conditionFulfilled)
- {
- printf("Fulfilled condition not yet implemented @ PC=0x%04x\n", m_pc);
- }
- cycles = 1;
- pcAdvance = 1;
- break;
- }
-
- // Format 4: Branch Direct Group
- case 0x00: case 0x01:
- {
- DSP_LINE("3-20")
- // goto JA : (page 3-20) (DONE)
- const uint16_t JA = (op & 0x0fff) | (m_pc & 0xf000);
- m_pc = JA;
- cycles = 2;
- pcAdvance = 0;
- break;
- }
-
- case 0x10: case 0x11:
- {
- DSP_LINE("3-23")
- // call JA : (page 3-23)
- const uint16_t JA = (op & 0x0fff) | (m_pc & 0xf000);
- m_pr = m_pc + 1;
- m_pc = JA;
- cycles = 2;
- pcAdvance = 0;
- break;
- }
-
- // Format 5: Branch Indirect Group
- case 0x18:
- {
- DSP_LINE("3-21")
- // goto B : (page 3-21)
- const uint8_t B = (op & 0x0700) >> 8;
- switch (B)
- {
- case 0x00: m_pc = m_pr; break;
- case 0x01: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
- case 0x02: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
- case 0x03: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
- default: logerror("DSP16: Invalid branch indirect instruction executed at PC=0x%04x\n.", m_pc); break;
- }
- cycles = 2;
- pcAdvance = 0;
- break;
- }
-
- // Format 6: Contitional Branch Qualifier/Software Interrupt (icall)
- case 0x1a:
- {
- DSP_LINE("3-22")
- // if CON [goto/call/return] : (page 3-22)
- const uint8_t CON = (op & 0x001f);
- bool conditionFulfilled = conditionTest(CON);
- cycles = 3; // TODO: This may need to interact with the next opcode to make sure it doesn't exceed 3?
- pcAdvance = 1;
- if (!conditionFulfilled)
- {
- pcAdvance = 2;
- }
- break;
- }
-
- // Format 7: Data Move Group
- case 0x09: case 0x0b:
- {
- DSP_LINE("3-29")
- // R = aS : (page 3-29)
- // TODO: Fix register pdxX (pc=338)
- const uint8_t R = (op & 0x03f0) >> 4;
- const uint8_t S = (op & 0x1000) >> 12;
- void* destinationReg = registerFromRTable(R);
- uint64_t* sourceReg = (S) ? &m_a1 : &m_a0;
- uint16_t sourceValue = (*sourceReg & 0x0ffff0000U) >> 16;
- writeRegister(destinationReg, sourceValue);
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x08:
- {
- DSP_LINE("3-30")
- // aT = R : (page 3-30)
- const uint8_t R = (op & 0x03f0) >> 4;
- const uint8_t aT = (op & 0x0400) >> 10;
- uint64_t* destinationReg = nullptr;
- switch(aT)
- {
- case 0: destinationReg = &m_a1; break;
- case 1: destinationReg = &m_a0; break;
- default: break;
- }
- void* sourceReg = registerFromRTable(R);
- *destinationReg &= 0x00000ffffU;
- *destinationReg |= (*(uint16_t*)sourceReg) << 16; // TODO: Fix for all registers
- if (*(uint16_t*)sourceReg & 0x8000)
- *destinationReg |= 0xf00000000U;
- // TODO: Special function encoding
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x0f:
- {
- DSP_LINE("3-32")
- // R = Y : (page 3-32)
- const uint8_t Y = (op & 0x000f);
- const uint8_t R = (op & 0x03f0) >> 4;
- uint16_t* sourceReg = registerFromYFieldUpper(Y);
- void* destinationReg = registerFromRTable(R);
- writeRegister(destinationReg, data_read(*sourceReg));
- executeYFieldPost(Y);
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x0c:
- {
- DSP_LINE("3-33")
- // Y = R : (page 3-33)
- // TODO: Zero & Sign extend i, c0, c1, c2, and auc
- const uint8_t Y = (op & 0x000f);
- const uint8_t R = (op & 0x03f0) >> 4;
- uint16_t* destinationReg = registerFromYFieldUpper(Y);
- uint16_t* sourceReg = (uint16_t*)registerFromRTable(R); // TODO: This won't work for certain registers!
- data_write(*destinationReg, *sourceReg); // Fix in data_write() maybe?
- executeYFieldPost(Y);
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x0d:
- {
- DSP_LINE("?")
- // Z : R
- //const uint8_t Z = (op & 0x000f);
- //const uint8_t R = (op & 0x03f0) >> 4;
- break;
- }
-
- // Format 8: Data Move (immediate operand - 2 words)
- case 0x0a:
- {
- DSP_LINE("3-28")
- // R = N : (page 3-28) (DONE)
- // NOTE: The docs speak of register sources & sign extension, but this is a register
- // destination, so, typo? If so, what does one do with the overflow bits?
- const uint8_t R = (op & 0x03f0) >> 4;
- const uint16_t iVal = opcode_read(1);
- void* destinationReg = registerFromRTable(R);
- writeRegister(destinationReg, iVal);
- cycles = 2;
- pcAdvance = 2;
- break;
- }
-
- // Format 9: Short Immediate Group
- case 0x02: case 0x03:
- {
- DSP_LINE("3-27")
- // R = M : (page 3-27)
- // TODO: Figure out notes about the DSP16A vs the DSP16. 9 bit is very DSP16...
- const uint16_t M = (op & 0x01ff);
- const uint8_t R = (op & 0x0e00) >> 9;
- void* destinationReg = registerFromRImmediateField(R);
- // Sign extend if the destination is j or k
- uint16_t mValue = M;
- if (destinationReg == &m_j || destinationReg == &m_k)
- {
- if (mValue & 0x0100) mValue |= 0xfe00;
- }
- writeRegister(destinationReg, mValue);
- cycles = 1;
- pcAdvance = 1;
- break;
- }
-
- // Format 10: do - redo
- case 0x0e:
- {
- DSP_LINE("3-25/3-26")
- // do|redo K : (pages 3-25 & 3-26)
- // TODO: The timings are intricate to say the least...
- const uint8_t K = (op & 0x007f);
- const uint8_t NI = (op & 0x0780) >> 7;
- if (NI != 0)
- {
- // Do
- m_cacheStart = m_pc + 1;
- m_cacheEnd = m_pc + 1 + NI;
- m_cacheIterations = K-1; // -1 because we check the counter @ the end
- cycles = 1;
- pcAdvance = 1;
- }
- else
- {
- // Redo
- m_cacheIterations = K-1; // -1 because we check the counter @ the end
- m_cacheRedoNextPC = m_pc + 1;
- m_pc = m_cacheStart;
- cycles = 2;
- pcAdvance = 0;
- }
- break;
- }
-
- // RESERVED
- case 0x1e:
- {
- DSP_LINE("XXX")
- break;
- }
-
- // UNKNOWN
- default:
- {
- DSP_LINE("XXX")
- break;
- }
- }
-
- // Handle end-of-cache conditions for do|redos
- if (m_cacheIterations == 0 && m_cacheRedoNextPC != CACHE_INVALID)
- {
- // You've reached the end of a cache loop after a redo opcode.
- m_pc = m_cacheRedoNextPC;
- m_cacheRedoNextPC = CACHE_INVALID;
- pcAdvance = 0;
- }
- if (m_cacheIterations > 0 && (m_pc+pcAdvance == m_cacheEnd))
- {
- // A regular iteration on a cached loop.
- m_cacheIterations--;
- m_pc = m_cacheStart;
- pcAdvance = 0;
- }
-}
diff --git a/src/devices/sound/qsound.cpp b/src/devices/sound/qsound.cpp
index 39fad698a72..d0c3852becf 100644
--- a/src/devices/sound/qsound.cpp
+++ b/src/devices/sound/qsound.cpp
@@ -2,8 +2,8 @@
// copyright-holders:Paul Leaman, Miguel Angel Horna
/***************************************************************************
- Capcom System QSound(tm)
- ========================
+ Capcom System QSound™
+ =====================
Driver by Paul Leaman and Miguel Angel Horna
@@ -40,28 +40,13 @@ DEFINE_DEVICE_TYPE(QSOUND, qsound_device, "qsound", "Q-Sound")
// chip decapped by siliconpr0n clearly shows 3x as much ROM as that, a total
// of 12288 words of internal ROM.
// The older DSP16 non-a part has 2048 words of ROM.
-void qsound_device::dsp16_program_map(address_map &map)
-{
- map(0x0000, 0x2fff).rom();
-}
-
-// data map for the DSP16A; again, Western Electric/AT&T expanded the size of
-// the ram over time.
-// As originally released, the DSP16A had 1024 words of internal RAM,
-// but this was expanded to 2048 words in the DL-1425 decap.
-// The older DSP16 non-a part has 512 words of RAM.
-void qsound_device::dsp16_data_map(address_map &map)
-{
- map.unmap_value_high();
- map(0x0000, 0x07ff).ram();
-}
-
-// ROM definition for the Qsound program ROM
+// DSP internal ROM region
ROM_START( qsound )
- ROM_REGION( 0x6000, "qsound", 0 )
- ROM_LOAD16_WORD( "dl-1425.bin", 0x0000, 0x6000, CRC(d6cf5ef5) SHA1(555f50fe5cdf127619da7d854c03f4a244a0c501) )
+ ROM_REGION( 0x2000, "dsp", 0 )
+ ROM_LOAD16_WORD_SWAP( "dl-1425.bin", 0x0000, 0x2000, CRC(d6cf5ef5) SHA1(555f50fe5cdf127619da7d854c03f4a244a0c501) )
+ ROM_IGNORE( 0x4000 )
ROM_END
@@ -74,12 +59,12 @@ ROM_END
//-------------------------------------------------
qsound_device::qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, QSOUND, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- device_rom_interface(mconfig, *this, 24),
- m_cpu(*this, "qsound"),
- m_data(0),
- m_stream(nullptr)
+ : device_t(mconfig, QSOUND, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , device_rom_interface(mconfig, *this, 24)
+ , m_dsp(*this, "dsp")
+ , m_stream(nullptr)
+ , m_data(0)
{
}
@@ -100,9 +85,8 @@ const tiny_rom_entry *qsound_device::device_rom_region() const
//-------------------------------------------------
MACHINE_CONFIG_START(qsound_device::device_add_mconfig)
- MCFG_CPU_ADD("qsound", DSP16, DERIVED_CLOCK(1, 1))
- MCFG_CPU_PROGRAM_MAP(dsp16_program_map)
- MCFG_CPU_DATA_MAP(dsp16_data_map)
+ MCFG_CPU_ADD("dsp", DSP16A, DERIVED_CLOCK(1, 1))
+ MCFG_DEVICE_DISABLE()
MACHINE_CONFIG_END
@@ -122,7 +106,7 @@ void qsound_device::rom_bank_updated()
void qsound_device::device_start()
{
- m_stream = stream_alloc(0, 2, clock() / 166); // /166 clock divider?
+ m_stream = stream_alloc(0, 2, clock() / 15 / 166); // /166 clock divider?
// create pan table
for (int i = 0; i < 33; i++)
@@ -152,6 +136,10 @@ void qsound_device::device_start()
}
}
+void qsound_device::device_reset()
+{
+}
+
//-------------------------------------------------
// sound_stream_update - handle a stream update
diff --git a/src/devices/sound/qsound.h b/src/devices/sound/qsound.h
index a206446f670..36ca47896d5 100644
--- a/src/devices/sound/qsound.h
+++ b/src/devices/sound/qsound.h
@@ -2,10 +2,9 @@
// copyright-holders:Paul Leaman, Miguel Angel Horna
/*********************************************************
- Capcom Q-Sound system
+ Capcom System QSound™
*********************************************************/
-
#ifndef MAME_SOUND_QSOUND_H
#define MAME_SOUND_QSOUND_H
@@ -13,46 +12,44 @@
#include "cpu/dsp16/dsp16.h"
-#define QSOUND_CLOCK 4000000 /* default 4MHz clock (60MHz/15?) */
+// default 60MHz clock (divided by 2 for DSP core clock, and then by 1248 for sample rate)
+#define QSOUND_CLOCK 60_MHz_XTAL
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
-#define MCFG_QSOUND_ADD(_tag, _clock) \
- MCFG_DEVICE_ADD(_tag, QSOUND, _clock)
-#define MCFG_QSOUND_REPLACE(_tag, _clock) \
- MCFG_DEVICE_REPLACE(_tag, QSOUND, _clock)
-
// ======================> qsound_device
-class qsound_device : public device_t,
- public device_sound_interface,
- public device_rom_interface
+class qsound_device : public device_t, public device_sound_interface, public device_rom_interface
{
public:
- qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ qsound_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
DECLARE_WRITE8_MEMBER(qsound_w);
DECLARE_READ8_MEMBER(qsound_r);
- void dsp16_data_map(address_map &map);
- void dsp16_program_map(address_map &map);
protected:
- // device-level overrides
- const tiny_rom_entry *device_rom_region() const override;
+ // device_t implementation
+ tiny_rom_entry const *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
+ virtual void device_reset() override;
- // sound stream update overrides
+ // device_sound_interface implementation
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
- // device_rom_interface overrides
+ // device_rom_interface implementation
virtual void rom_bank_updated() override;
private:
+
+ // MAME resources
+ required_device<dsp16_device_base> m_dsp;
+ sound_stream *m_stream;
+
struct qsound_channel
{
uint32_t bank; // bank
@@ -69,11 +66,8 @@ private:
uint32_t step_ptr; // current offset counter
} m_channel[16];
- required_device<dsp16_device> m_cpu;
-
int m_pan_table[33]; // pan volume table
uint16_t m_data; // register latch data
- sound_stream *m_stream; // audio stream
inline int8_t read_sample(uint32_t offset) { return (int8_t)read_byte(offset); }
void write_data(uint8_t address, uint16_t data);
diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp
index bf94da8cdce..9a3e9978053 100644
--- a/src/emu/validity.cpp
+++ b/src/emu/validity.cpp
@@ -1598,7 +1598,7 @@ void validity_checker::validate_roms(device_t &root)
if (!ROMENTRY_ISREGIONEND(romp) && current_length > 0)
{
items_since_region++;
- if (ROM_GETOFFSET(romp) + ROM_GETLENGTH(romp) > current_length)
+ if (!ROMENTRY_ISIGNORE(romp) && (ROM_GETOFFSET(romp) + ROM_GETLENGTH(romp) > current_length))
osd_printf_error("ROM '%s' extends past the defined memory region\n", last_name);
}
}
diff --git a/src/mame/drivers/cps1.cpp b/src/mame/drivers/cps1.cpp
index 5ac0dced03b..6e63ca98bff 100644
--- a/src/mame/drivers/cps1.cpp
+++ b/src/mame/drivers/cps1.cpp
@@ -3456,7 +3456,7 @@ MACHINE_CONFIG_START(cps_state::qsound)
MCFG_DEVICE_REMOVE("2151")
MCFG_DEVICE_REMOVE("oki")
- MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
+ MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
MACHINE_CONFIG_END
diff --git a/src/mame/drivers/cps2.cpp b/src/mame/drivers/cps2.cpp
index c6f2569ffdb..b2b23e596a3 100644
--- a/src/mame/drivers/cps2.cpp
+++ b/src/mame/drivers/cps2.cpp
@@ -1336,7 +1336,7 @@ MACHINE_CONFIG_START(cps_state::cps2)
/* sound hardware */
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
- MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
+ MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
MACHINE_CONFIG_END
diff --git a/src/mame/drivers/vgmplay.cpp b/src/mame/drivers/vgmplay.cpp
index 43607e47968..5a78efbd45c 100644
--- a/src/mame/drivers/vgmplay.cpp
+++ b/src/mame/drivers/vgmplay.cpp
@@ -1757,7 +1757,7 @@ MACHINE_CONFIG_START(vgmplay_state::vgmplay)
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
- MCFG_QSOUND_ADD("qsound", 4000000)
+ MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
MCFG_DEVICE_ADDRESS_MAP(0, qsound_map)
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
diff --git a/src/mame/drivers/zn.cpp b/src/mame/drivers/zn.cpp
index 54bbd44e76e..e8d39163157 100644
--- a/src/mame/drivers/zn.cpp
+++ b/src/mame/drivers/zn.cpp
@@ -661,7 +661,7 @@ MACHINE_CONFIG_START(zn_state::coh1000c)
MCFG_DEVICE_MODIFY("soundlatch")
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
- MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
+ MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
MACHINE_CONFIG_END
@@ -687,7 +687,7 @@ MACHINE_CONFIG_START(zn_state::coh1002c)
MCFG_DEVICE_MODIFY("soundlatch")
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
- MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
+ MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
MACHINE_CONFIG_END
@@ -849,7 +849,7 @@ MACHINE_CONFIG_START(zn_state::coh3002c)
MCFG_DEVICE_MODIFY("soundlatch")
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
- MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
+ MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
MACHINE_CONFIG_END