summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/dspp
diff options
context:
space:
mode:
author mooglyguy <therealmogminer@gmail.com>2018-12-22 17:06:23 +0100
committer mooglyguy <therealmogminer@gmail.com>2018-12-22 17:06:47 +0100
commitdc8834b8dca7f63288f3f512d7e8600356485808 (patch)
treecb81425c648108f02542ae493e91ec96ad3d2ac4 /src/devices/cpu/dspp
parent1fd2f33b314b18237e80d8c6a9f70b580854802a (diff)
Last round of macro removals before the freeze. (nw)
-sound/discrete, okim6295: Removed MCFG macros. [Ryan Holtz] -norautp, osi, audio/mario: Removed MACHINE_CONFIG macros. [Ryan Holtz] -vsmile: Split into its own driver from vii.cpp. [Ryan Holtz] -vii: Fixed broken controller inputs. [Ryan Holtz] -konamim2: Massive update. Most games work, but are still marked non-working due to rare MAME crashes in the PPC DRC. [Phil Bennett, Ryan Holtz]
Diffstat (limited to 'src/devices/cpu/dspp')
-rw-r--r--src/devices/cpu/dspp/dspp.cpp2646
-rw-r--r--src/devices/cpu/dspp/dspp.h337
-rw-r--r--src/devices/cpu/dspp/dsppdasm.cpp124
-rw-r--r--src/devices/cpu/dspp/dsppdasm.h22
-rw-r--r--src/devices/cpu/dspp/dsppdrc.cpp970
-rw-r--r--src/devices/cpu/dspp/dsppfe.cpp625
-rw-r--r--src/devices/cpu/dspp/dsppfe.h72
7 files changed, 4796 insertions, 0 deletions
diff --git a/src/devices/cpu/dspp/dspp.cpp b/src/devices/cpu/dspp/dspp.cpp
new file mode 100644
index 00000000000..d8d8e7055e1
--- /dev/null
+++ b/src/devices/cpu/dspp/dspp.cpp
@@ -0,0 +1,2646 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dspp.c
+
+ Core implementation for the portable 3DO (M2) DSPP emulator.
+ DSPP = Don's Super Performing Processor
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "dspp.h"
+#include "dsppfe.h"
+#include "dsppdasm.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+enum
+{
+ DSPP_PC = 1,
+ DSPP_ACC,
+ DSPP_FLAGS,
+ DSPP_CLOCK,
+};
+
+
+// DRC
+#define SINGLE_INSTRUCTION_MODE (0)
+
+
+#define CACHE_SIZE (4 * 1024 * 1024) // FIXME
+// FIXME!!!
+/* compilation boundaries -- how far back/forward does the analysis extend? */
+#define COMPILE_BACKWARDS_BYTES 128
+#define COMPILE_FORWARDS_BYTES 512
+#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4))
+#define COMPILE_MAX_SEQUENCE 64
+
+/* exit codes */
+#define EXECUTE_OUT_OF_CYCLES 0
+#define EXECUTE_MISSING_CODE 1
+#define EXECUTE_UNMAPPED_CODE 2
+#define EXECUTE_RESET_CACHE 3
+
+
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+//#define DSPI_FLAG_CC_CARRY 0x0001
+//#define DSPI_FLAG_CC_ZERO 0x0002
+//#define DSPI_FLAG_CC_NEG 0x0004
+//#define DSPI_FLAG_CC_OVER 0x0008
+//#define DSPI_FLAG_CC_EXACT 0x0010
+//#define DSPI_FLAG_AUDLOCK 0x0020
+//#define DSPI_FLAG_SLEEP 0x0040
+//#define DSPI_FLAG_CC_MASK 0x001f
+
+#define DSPX_CONTROL_GWILLING 0x0001
+#define DSPX_CONTROL_STEP_CYCLE 0x0002
+#define DSPX_CONTROL_STEP_PC 0x0004
+#define DSPX_CONTROL_SNOOP 0x0008
+
+#define DSPX_RESET_DSPP 0x0001
+#define DSPX_RESET_INPUT 0x0002
+#define DSPX_RESET_OUTPUT 0x0004
+
+#define DSPX_F_DMA_NEXTVALID 0x0001
+#define DSPX_F_DMA_GO_FOREVER 0x0002
+#define DSPX_F_INT_DMANEXT_EN 0x0004
+#define DSPX_F_SHADOW_SET_DMANEXT 0x00040000
+#define DSPX_F_SHADOW_SET_FOREVER 0x00020000
+#define DSPX_F_SHADOW_SET_NEXTVALID 0x00010000
+#define DSPX_F_SHADOW_SET_ADDRESS_COUNT 0x80000000
+
+#define DSPX_F_INT_TIMER 0x00000100
+#define DSPX_F_INT_INPUT_UNDER 0x00000080
+#define DSPX_F_INT_INPUT_OVER 0x00000040
+#define DSPX_F_INT_OUTPUT_UNDER 0x00000020
+#define DSPX_F_INT_OUTPUT_OVER 0x00000010
+#define DSPX_F_INT_UNDEROVER 0x00000008
+#define DSPX_F_INT_CONSUMED 0x00000002
+#define DSPX_F_INT_DMANEXT 0x00000001
+
+#define DSPX_F_INT_ALL_DMA (DSPX_F_INT_DMANEXT | DSPX_F_INT_CONSUMED | DSPX_F_INT_UNDEROVER)
+
+#define DSPX_FLD_INT_SOFT_WIDTH 16 /* width of the field and the number of interrupts */
+#define DSPX_FLD_INT_SOFT_SHIFT 16
+#define DSPX_FLD_INT_SOFT_MASK (0xffff0000)
+
+
+
+//**************************************************************************
+// INTERNAL MEMORY MAPS
+//**************************************************************************
+
+void dspp_device::code_map(address_map &map)
+{
+ map(0x000, 0x3ff).ram();
+}
+
+void dspp_device::data_map(address_map &map)
+{
+ map(0x000, 0x2df).ram();
+ map(0x2f0, 0x2f1).r(FUNC(dspp_device::input_r));
+ map(0x2e0, 0x2e7).w(FUNC(dspp_device::output_w));
+ map(0x300, 0x37f).rw(FUNC(dspp_device::fifo_osc_r), FUNC(dspp_device::fifo_osc_w));
+ map(0x3bc, 0x3bc).nopr(); // ?
+ map(0x3d6, 0x3d6).w(FUNC(dspp_device::input_control_w));
+ map(0x3d7, 0x3d7).w(FUNC(dspp_device::output_control_w));
+ map(0x3de, 0x3de).r(FUNC(dspp_device::input_status_r));
+ map(0x3df, 0x3df).r(FUNC(dspp_device::output_status_r));
+ map(0x3e6, 0x3e6).w(FUNC(dspp_device::cpu_int_w));
+ map(0x3ee, 0x3ee).rw(FUNC(dspp_device::pc_r), FUNC(dspp_device::pc_w));
+ map(0x3f6, 0x3f6).rw(FUNC(dspp_device::audlock_r), FUNC(dspp_device::audlock_w));
+ map(0x3f7, 0x3f7).rw(FUNC(dspp_device::clock_r), FUNC(dspp_device::clock_w));
+ map(0x3ff, 0x3ff).r(FUNC(dspp_device::noise_r));
+}
+
+
+
+//**************************************************************************
+// DEVICE INTERFACE
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(DSPP, dspp_device, "dspp", "3DO DSPP")
+
+//-------------------------------------------------
+// dspp_device - constructor
+//-------------------------------------------------
+
+dspp_device::dspp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : dspp_device(mconfig, DSPP, tag, owner, clock, address_map_constructor(FUNC(dspp_device::code_map), this),
+ address_map_constructor(FUNC(dspp_device::data_map), this))
+{
+}
+
+dspp_device::dspp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor code_map_ctor, address_map_constructor data_map_ctor)
+ : cpu_device(mconfig, type, tag, owner, clock),
+ m_int_handler(*this),
+ m_dma_read_handler(*this),
+ m_dma_write_handler(*this),
+ m_code_config("code", ENDIANNESS_BIG, 16, 10, -1, code_map_ctor),
+ m_data_config("data", ENDIANNESS_BIG, 16, 10, -1, data_map_ctor),
+ m_code(nullptr),
+ m_data(nullptr),
+ m_output_fifo_start(0),
+ m_output_fifo_count(0),
+ m_dspx_control(0),
+ m_dspx_reset(0),
+ m_dspx_int_enable(0),
+ m_dspx_channel_enable(0),
+ m_dspx_channel_complete(0),
+ m_dspx_channel_direction(0),
+ m_dspx_channel_8bit(0),
+ m_dspx_channel_sqxd(0),
+ m_dspx_shadow_current_addr(0),
+ m_dspx_shadow_current_count(0),
+ m_dspx_shadow_next_addr(0),
+ m_dspx_shadow_next_count(0),
+ m_dspx_dmanext_int(0),
+ m_dspx_dmanext_enable(0),
+ m_dspx_consumed_int(0),
+ m_dspx_consumed_enable(0),
+ m_dspx_underover_int(0),
+ m_dspx_underover_enable(0),
+ m_dspx_audio_time(0),
+ m_dspx_audio_duration(0),
+ m_cache(CACHE_SIZE),
+ m_drcuml(nullptr),
+ m_drcfe(nullptr),
+ m_drcoptions(0)
+{
+#if 0
+ memset(m_core->m_stack, 0, sizeof(m_core->m_stack));
+ memset(m_core->m_rbase, 0, sizeof(m_core->m_rbase));
+ memset(m_outputs, 0, sizeof(m_outputs));
+ memset(m_output_fifo, 0, sizeof(m_output_fifo));
+ memset(m_fifo_dma, 0, sizeof(m_fifo_dma));
+#endif
+}
+
+
+//-------------------------------------------------
+// device_start - start up the device
+//-------------------------------------------------
+
+void dspp_device::device_start()
+{
+ // DSPP DRC is not yet ready for prime time
+ m_isdrc = false;//allow_drc();
+
+ m_core = (dspp_internal_state *)m_cache.alloc_near(sizeof(dspp_internal_state));
+ memset(m_core, 0, sizeof(dspp_internal_state));
+
+ uint32_t flags = 0;
+ m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, flags, 1, 16, 0);
+
+ m_drcfe = std::make_unique<dspp_frontend>(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE);
+
+ // Resolve our callbacks
+ m_int_handler.resolve_safe();
+ m_dma_read_handler.resolve_safe(0);
+ m_dma_write_handler.resolve_safe();
+
+ // Get our address spaces
+ m_code = &space(AS_PROGRAM);
+ m_data = &space(AS_DATA);
+ auto code_cache = m_code->cache<1, -1, ENDIANNESS_BIG>();
+ m_code_cache = code_cache;
+ m_codeptr = [code_cache](offs_t address) -> const void * { return code_cache->read_ptr(address); };
+
+ // Register our state for the debugger
+ state_add(DSPP_PC, "PC", m_core->m_pc);
+ state_add(DSPP_ACC, "ACC", m_core->m_acc);
+ state_add(STATE_GENPC, "GENPC", m_core->m_pc).noshow();
+#if 0
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_core->m_flags).callimport().callexport().formatstr("%6s").noshow();
+ state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow();
+ state_add(STATE_GENSP, "GENSP", m_src2val[REGBASE + 31]).noshow();
+
+ state_add(DSPP_PS, "PS", m_core->m_flagsio).callimport().callexport();
+ for (int regnum = 0; regnum < 32; regnum++)
+ state_add(DSPP_R0 + regnum, tempstr.format("R%d", regnum), m_src2val[REGBASE + regnum]);
+#endif
+
+ // Register our state for saving
+ save_item(NAME(m_core->m_pc));
+ save_item(NAME(m_core->m_stack));
+ save_item(NAME(m_core->m_stack_ptr));
+ save_item(NAME(m_core->m_rbase));
+ save_item(NAME(m_core->m_acc));
+ save_item(NAME(m_core->m_tclock));
+
+ save_item(NAME(m_core->m_flag_carry));
+ save_item(NAME(m_core->m_flag_zero));
+ save_item(NAME(m_core->m_flag_neg));
+ save_item(NAME(m_core->m_flag_over));
+ save_item(NAME(m_core->m_flag_exact));
+ save_item(NAME(m_core->m_flag_audlock));
+ save_item(NAME(m_core->m_flag_sleep));
+
+ save_item(NAME(m_outputs));
+ save_item(NAME(m_output_fifo_start));
+ save_item(NAME(m_output_fifo_count));
+
+ for (uint32_t i = 0; i < NUM_DMA_CHANNELS; ++i)
+ {
+ save_item(NAME(m_fifo_dma[i].m_current_addr), i);
+ save_item(NAME(m_fifo_dma[i].m_current_count), i);
+ save_item(NAME(m_fifo_dma[i].m_next_addr), i);
+ save_item(NAME(m_fifo_dma[i].m_next_count), i);
+ save_item(NAME(m_fifo_dma[i].m_prev_value), i);
+ save_item(NAME(m_fifo_dma[i].m_prev_current), i);
+ save_item(NAME(m_fifo_dma[i].m_go_forever), i);
+ save_item(NAME(m_fifo_dma[i].m_next_valid), i);
+ save_item(NAME(m_fifo_dma[i].m_reserved), i);
+ save_item(NAME(m_fifo_dma[i].m_fifo), i);
+ save_item(NAME(m_fifo_dma[i].m_dma_ptr), i);
+ save_item(NAME(m_fifo_dma[i].m_dspi_ptr), i);
+ save_item(NAME(m_fifo_dma[i].m_depth), i);
+ }
+
+ save_item(NAME(m_last_frame_clock));
+ save_item(NAME(m_last_osc_count));
+ save_item(NAME(m_osc_phase));
+ save_item(NAME(m_osc_freq));
+
+ save_item(NAME(m_core->m_partial_int));
+
+ save_item(NAME(m_dspx_control));
+ save_item(NAME(m_dspx_reset));
+ save_item(NAME(m_dspx_int_enable));
+ save_item(NAME(m_dspx_channel_enable));
+ save_item(NAME(m_dspx_channel_complete));
+ save_item(NAME(m_dspx_channel_direction));
+ save_item(NAME(m_dspx_channel_8bit));
+ save_item(NAME(m_dspx_channel_sqxd));
+ save_item(NAME(m_dspx_shadow_current_addr));
+ save_item(NAME(m_dspx_shadow_current_count));
+ save_item(NAME(m_dspx_shadow_next_addr));
+ save_item(NAME(m_dspx_shadow_next_count));
+ save_item(NAME(m_dspx_dmanext_int));
+ save_item(NAME(m_dspx_dmanext_enable));
+ save_item(NAME(m_dspx_consumed_int));
+ save_item(NAME(m_dspx_consumed_enable));
+ save_item(NAME(m_dspx_underover_int));
+ save_item(NAME(m_dspx_underover_enable));
+ save_item(NAME(m_dspx_audio_time));
+ save_item(NAME(m_dspx_audio_duration));
+
+ // Set our instruction counter
+ set_icountptr(m_core->m_icount);
+
+ m_cache_dirty = true;
+}
+
+
+//-------------------------------------------------
+// device_reset - reset the device
+//-------------------------------------------------
+
+void dspp_device::device_reset()
+{
+ // initialize the state
+ m_core->m_pc = 0;
+ m_core->m_stack_ptr = 0;
+ m_output_fifo_start = 0;
+ m_output_fifo_count = 0;
+
+ m_core->m_flag_audlock = 0;
+ m_core->m_flag_sleep = 0;
+ m_core->m_stack_ptr = 0;
+ m_core->m_writeback = ~1; // TODO
+ set_rbase(0, 0);
+
+ // TODO: CLEAR DMA CHANNELS
+
+ // Clear interrupts
+ m_core->m_partial_int = 0;
+ update_host_interrupt();
+
+ m_cache_dirty = true;
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return the configuration
+// of the CPU's address spaces
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector dspp_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_code_config),
+ std::make_pair(AS_DATA, &m_data_config)
+ };
+}
+
+
+//-------------------------------------------------
+// state_import - import state into the device,
+// after it has been set
+//-------------------------------------------------
+
+void dspp_device::state_import(const device_state_entry &entry)
+{
+
+}
+
+
+//-------------------------------------------------
+// state_export - export state from the device,
+// to a known location where it can be read
+//-------------------------------------------------
+
+void dspp_device::state_export(const device_state_entry &entry)
+{
+
+}
+
+
+//-------------------------------------------------
+// state_string_export - export state as a string
+// for the debugger
+//-------------------------------------------------
+
+void dspp_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ str = string_format("%c%c.%c%c%c%c%c",
+ m_core->m_flag_audlock ? 'A' : '.',
+ m_core->m_flag_sleep ? 'S' : '.',
+ m_core->m_flag_carry ? 'C' : '.',
+ m_core->m_flag_zero ? 'Z' : '.',
+ m_core->m_flag_neg ? 'N' : '.',
+ m_core->m_flag_over ? 'V' : '.',
+ m_core->m_flag_exact ? 'E' : '.');
+ break;
+ }
+}
+
+std::unique_ptr<util::disasm_interface> dspp_device::create_disassembler()
+{
+ return std::make_unique<dspp_disassembler>();
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// update_pc -
+//-------------------------------------------------
+
+inline void dspp_device::update_pc()
+{
+ ++m_core->m_pc;
+}
+
+inline void dspp_device::update_ticks()
+{
+ --m_core->m_tclock;
+ --m_core->m_icount;
+}
+
+
+//-------------------------------------------------
+// readop - Read an opcode at the given address
+//-------------------------------------------------
+
+uint16_t dspp_device::read_op(offs_t pc)
+{
+ return m_code_cache->read_word(pc);
+}
+
+
+//-------------------------------------------------
+// read_data - Read a word from the data space
+//-------------------------------------------------
+
+inline uint16_t dspp_device::read_data(offs_t addr)
+{
+ return m_data->read_word(addr);
+}
+
+
+//-------------------------------------------------
+// write_data - Write a word to the data space
+//-------------------------------------------------
+
+inline void dspp_device::write_data(offs_t addr, uint16_t data)
+{
+ m_data->write_word(addr, data);
+}
+
+
+//-------------------------------------------------
+// get_interrupt_state -
+//-------------------------------------------------
+
+uint32_t dspp_device::get_interrupt_state()
+{
+ uint32_t host_int = m_core->m_partial_int;
+
+ if (m_dspx_dmanext_int & m_dspx_dmanext_enable)
+ host_int |= DSPX_F_INT_DMANEXT;
+
+ if (m_dspx_consumed_int & m_dspx_consumed_enable)
+ host_int |= DSPX_F_INT_CONSUMED;
+
+ return host_int;
+}
+
+
+//-------------------------------------------------
+// update_host_interrupt -
+//-------------------------------------------------
+
+void dspp_device::update_host_interrupt()
+{
+ // TODO: Underflow/overflow interrupts
+ m_int_handler(get_interrupt_state() & m_dspx_int_enable ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// parse_operand - Parse instruction operands
+//-------------------------------------------------
+
+void dspp_device::parse_operands(uint32_t numops)
+{
+ uint32_t addr, val = 0xBAD;
+ uint32_t opidx = 0;
+ uint32_t operand = 0;
+ uint32_t numregs = 0;
+
+ for (uint32_t i = 0; i < MAX_OPERANDS; ++i)
+ {
+ // Reset operands
+ m_operands[i].value = -1;
+ m_operands[i].addr = -1;
+ }
+
+ // Reset global op index
+ m_core->m_opidx = 0;
+
+ while (opidx < numops)
+ {
+ operand = read_op(m_core->m_pc);
+ update_pc();
+ update_ticks();
+
+ if (operand & 0x8000)
+ {
+ // Immediate value
+ if ((operand & 0xc000) == 0xc000)
+ {
+ val = operand & 0x1fff;
+
+ if (operand & 0x2000)
+ {
+ // Left justify
+ val = val << 3;
+ }
+ else
+ {
+ // Sign extend if right justified
+ if (val & 0x1000)
+ val |= 0xe000;
+ }
+ m_operands[opidx++].value = val;
+ }
+ else if((operand & 0xe000) == 0x8000)
+ {
+ // Address operand
+ addr = operand & 0x03ff;
+
+ if (operand & 0x0400)
+ {
+ // Indirect
+ addr = read_data(addr);
+ }
+ m_operands[opidx].addr = addr;
+
+ if (operand & 0x0800)
+ {
+ // Write Back
+ m_core->m_writeback = addr;
+ }
+ ++opidx;
+ }
+ else if ((operand & 0xe000) == 0xa000)
+ {
+ // 1 or 2 register operand
+ numregs = (operand & 0x0400) ? 2 : 1;
+ }
+ }
+ else
+ {
+ numregs = 3;
+ }
+
+ if (numregs > 0)
+ {
+ uint32_t shifter, regdi;
+
+ // Shift successive register operands from a single operand word
+ for (uint32_t i = 0; i < numregs; ++i)
+ {
+ shifter = ((numregs - i) - 1) * 5;
+ regdi = (operand >> shifter) & 0x1f;
+ addr = translate_reg(regdi & 0xf);
+
+ if (regdi & 0x0010)
+ {
+ // Indirect?
+ addr = read_data(addr);
+ }
+
+ if (numregs == 2)
+ {
+ if ((i == 0) && (operand & 0x1000))
+ m_core->m_writeback = addr;
+ else if ((i == 1) && (operand & 0x0800))
+ m_core->m_writeback = addr;
+ }
+ else if (numregs == 1)
+ {
+ if (operand & 0x800)
+ m_core->m_writeback = addr;
+ }
+
+ m_operands[opidx++].addr = addr;
+ }
+ numregs = 0;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// read_next_operand - Return the value encoded by
+// the next operand
+//-------------------------------------------------
+
+uint16_t dspp_device::read_next_operand()
+{
+ int32_t value = m_operands[m_core->m_opidx].value;
+
+ if (value < 0)
+ value = read_data(m_operands[m_core->m_opidx].addr);
+
+ // Next operand
+ ++m_core->m_opidx;
+
+ return value;
+}
+
+
+//-------------------------------------------------
+// write_next_operand - Write to the address
+// encoded by the next operand
+//-------------------------------------------------
+
+void dspp_device::write_next_operand(uint16_t value)
+{
+ int32_t addr = m_operands[m_core->m_opidx].addr;
+
+ assert(addr != -1);
+
+ write_data(addr, value);
+
+ // Advance to the next operand
+ ++m_core->m_opidx;
+}
+
+
+//-------------------------------------------------
+// push_pc - Push program counter onto the stack
+//-------------------------------------------------
+
+inline void dspp_device::push_pc()
+{
+ if (m_core->m_stack_ptr < PC_STACK_DEPTH)
+ m_core->m_stack[m_core->m_stack_ptr++] = m_core->m_pc;
+ else
+ fatalerror("DSPP stack overflow!");
+}
+
+
+//-------------------------------------------------
+// pop_pc - Pop program counter from the stack
+//-------------------------------------------------
+
+inline uint16_t dspp_device::pop_pc()
+{
+ if (m_core->m_stack_ptr == 0)
+ fatalerror("DSPP stack underflow!");
+
+ return m_core->m_stack[--m_core->m_stack_ptr];
+}
+
+
+//-------------------------------------------------
+// set_rbase - Set register address base
+//-------------------------------------------------
+
+inline void dspp_device::set_rbase(uint32_t base, uint32_t addr)
+{
+ switch (base)
+ {
+ case 4:
+ m_core->m_rbase[1] = addr + 4 - base;
+ break;
+ case 0:
+ m_core->m_rbase[0] = addr;
+ m_core->m_rbase[1] = addr + 4 - base;
+ // Intentional fall-through
+ case 8:
+ m_core->m_rbase[2] = addr + 8 - base;
+
+ case 12:
+ m_core->m_rbase[3] = addr + 12 - base;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// translate_reg - Translate register address
+//-------------------------------------------------
+
+inline uint16_t dspp_device::translate_reg(uint16_t reg)
+{
+ uint32_t base = (reg >> 2) & 3;
+ return m_core->m_rbase[base] + reg - (reg & ~3);
+}
+
+
+
+//**************************************************************************
+// CORE EXECUTION
+//**************************************************************************
+
+//-------------------------------------------------
+// execute_min_cycles - return minimum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+uint32_t dspp_device::execute_min_cycles() const
+{
+ return 1;
+}
+
+
+//-------------------------------------------------
+// execute_max_cycles - return maximum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+uint32_t dspp_device::execute_max_cycles() const
+{
+ return 5; // TODO ?
+}
+
+
+//-------------------------------------------------
+// execute_run - core execution loop
+//-------------------------------------------------
+
+void dspp_device::execute_run()
+{
+ if (m_isdrc)
+ {
+ // TODO: TEMPORARY HACK!
+ if (m_dspx_control & DSPX_CONTROL_GWILLING)
+ execute_run_drc();
+ else
+ m_core->m_icount = 0;
+ return;
+ }
+
+ bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0);
+
+ do
+ {
+ update_ticks();
+ update_fifo_dma();
+
+ // Only run if enabled
+ if (m_dspx_control & DSPX_CONTROL_GWILLING)
+ {
+ if (check_debugger)
+ debugger_instruction_hook(m_core->m_pc);
+
+ m_core->m_op = read_op(m_core->m_pc);
+ update_pc();
+
+ // Decode and execute
+ if (m_core->m_op & 0x8000)
+ exec_control();
+ else
+ exec_arithmetic();
+ }
+
+ } while (m_core->m_icount > 0);
+}
+
+
+
+//**************************************************************************
+// OPCODE IMPLEMENTATIONS
+//**************************************************************************
+
+//-------------------------------------------------
+// exec_super_special - Execute a super special
+// control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_super_special()
+{
+ uint32_t sel = (m_core->m_op >> 7) & 7;
+
+ switch (sel)
+ {
+ case 1: // BAC
+ {
+ m_core->m_pc = m_core->m_acc >> 4;
+ break;
+ }
+ case 4: // RTS
+ {
+ m_core->m_pc = pop_pc();
+ break;
+ }
+ case 5: // OP_MASK
+ {
+ // TODO
+ break;
+ }
+
+ case 7: // SLEEP
+ {
+ // TODO: How does sleep work?
+ --m_core->m_pc;
+ m_core->m_flag_sleep = 1;
+ break;
+ }
+
+ case 0: // NOP
+ case 2: // Unused
+ case 3:
+ case 6:
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// exec_special - Execute a special control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_special()
+{
+ switch ((m_core->m_op >> 10) & 7)
+ {
+ case 0:
+ {
+ exec_super_special();
+ break;
+ }
+ case 1: // JUMP
+ {
+ m_core->m_pc = m_core->m_op & 0x3ff;
+ break;
+ }
+ case 2: // JSR
+ {
+ push_pc();
+ m_core->m_pc = m_core->m_op & 0x3ff;
+ break;
+ }
+ case 3: // BFM
+ {
+ break;
+ }
+ case 4: // MOVEREG
+ {
+ uint32_t regdi = m_core->m_op & 0x3f;
+ uint32_t addr = translate_reg(regdi & 0xf);
+
+ // Indirect
+ if (regdi & 0x0010)
+ {
+ addr = read_data(addr);
+ break;
+ }
+
+ parse_operands(1);
+ write_data(addr, read_next_operand());
+ break;
+ }
+ case 5: // RBASE
+ {
+ set_rbase((m_core->m_op & 3) << 2, m_core->m_op & 0x3fc);
+ break;
+ }
+ case 6: // MOVED
+ {
+ parse_operands(1);
+ write_data(m_core->m_op & 0x3ff, read_next_operand());
+ break;
+ }
+ case 7: // MOVEI
+ {
+ parse_operands(1);
+ uint32_t addr = read_data(m_core->m_op & 0x3ff);
+ write_data(addr, read_next_operand());
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// exec_branch - Execute a branch control op
+//-------------------------------------------------
+
+void dspp_device::exec_branch()
+{
+ uint32_t mode = (m_core->m_op >> 13) & 3;
+ uint32_t select = (m_core->m_op >> 12) & 1;
+ uint32_t mask = (m_core->m_op >> 10) & 3;
+
+ bool flag0, flag1;
+
+ if (select == 0)
+ {
+ flag0 = m_core->m_flag_neg;
+ flag1 = m_core->m_flag_over;
+ }
+ else
+ {
+ flag0 = m_core->m_flag_carry;
+ flag1 = m_core->m_flag_zero;
+ }
+
+ bool mask0 = (mask & 2) != 0;
+ bool mask1 = (mask & 1) != 0;
+
+ bool branch = (flag0 || !mask0) && (flag1 || !mask1);
+
+ if (mode == 2)
+ branch = !branch;
+
+ if (branch)
+ m_core->m_pc = m_core->m_op & 0x3ff;
+}
+
+
+//-------------------------------------------------
+// exec_complex_branch - Execute a complex branch
+// control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_complex_branch()
+{
+ uint32_t type = (m_core->m_op >> 10) & 7;
+
+ const bool c = m_core->m_flag_carry;
+ const bool z = m_core->m_flag_zero;
+ const bool n = m_core->m_flag_neg;
+ const bool v = m_core->m_flag_over;
+ const bool x = m_core->m_flag_exact;
+
+ bool branch = false;
+
+ switch (type)
+ {
+ case 0: // BLT
+ branch = (n && !v) || (!n && v);
+ break;
+ case 1: // BLE
+ branch = ((n && !v) || (!n && v)) || z;
+ break;
+ case 2: // BGE
+ branch = ((n && v) || (!n && !v));
+ break;
+ case 3: // BGT
+ branch = ((n && v) || (!n && !v)) && !z;
+ break;
+ case 4: // BHI
+ branch = c && !z;
+ break;
+ case 5: // BLS
+ branch = !c || z;
+ break;
+ case 6: // BXS
+ branch = x;
+ break;
+ case 7: // BXC
+ branch = !x;
+ break;
+ }
+
+ if (branch)
+ m_core->m_pc = m_core->m_op & 0x3ff;
+}
+
+
+//-------------------------------------------------
+// exec_control - Execute a control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_control()
+{
+ uint32_t mode = (m_core->m_op >> 13) & 3;
+
+ switch (mode)
+ {
+ // Special
+ case 0:
+ {
+ exec_special();
+ break;
+ }
+
+ // Branches
+ case 1: case 2:
+ {
+ exec_branch();
+ break;
+ }
+
+ // Complex branches
+ case 3:
+ {
+ exec_complex_branch();
+ break;
+ }
+
+ default:
+ fatalerror("Invalid DSPP control instruction mode");
+ break;
+ }
+}
+
+//-------------------------------------------------
+// sign_extend8 - Sign extend 8-bits to 32-bits
+//-------------------------------------------------
+
+static inline int32_t sign_extend8(uint8_t val)
+{
+ return (int32_t)(int8_t)val;
+}
+
+
+//-------------------------------------------------
+// sign_extend16 - Sign extend 16-bits to 32-bits
+//-------------------------------------------------
+
+static inline int32_t sign_extend16(uint16_t val)
+{
+ return (int32_t)(int16_t)val;
+}
+
+
+//-------------------------------------------------
+// sign_extend20 - Sign extend 20-bits to 32-bits
+//-------------------------------------------------
+
+static inline int32_t sign_extend20(uint32_t val)
+{
+ if (val & 0x00080000)
+ return (int32_t)(0xfff00000 | val);
+ else
+ return (int32_t)val;
+}
+
+
+//-------------------------------------------------
+// exec_arithmetic - Execute an arithmetic op
+//-------------------------------------------------
+
+inline void dspp_device::exec_arithmetic()
+{
+ // Decode the various fields
+ uint32_t numops = (m_core->m_op >> 13) & 3;
+ uint32_t muxa = (m_core->m_op >> 10) & 3;
+ uint32_t muxb = (m_core->m_op >> 8) & 3;
+ uint32_t alu_op = (m_core->m_op >> 4) & 0xf;
+ uint32_t barrel_code = m_core->m_op & 0xf;
+
+ int32_t mul_res = 0;
+ uint32_t alu_res = 0;
+
+ // Check for operand overflow
+ if (numops == 0 && ((muxa == 1) || (muxa == 2) || (muxb == 1) || (muxb == 2)))
+ numops = 4;
+
+ // Implicit barrel shift
+ if (barrel_code == 8)
+ ++numops;
+
+ // Parse ops...
+ parse_operands(numops);
+
+ if (muxa == 3 || muxb == 3)
+ {
+ uint32_t mul_sel = (m_core->m_op >> 12) & 1;
+
+ int32_t op1 = sign_extend16(read_next_operand());
+ int32_t op2 = sign_extend16(mul_sel ? read_next_operand() : m_core->m_acc >> 4);
+
+ mul_res = (op1 * op2) >> 11;
+ }
+
+ int32_t alu_a, alu_b;
+
+ switch (muxa)
+ {
+ case 0:
+ {
+ alu_a = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_a = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_a = mul_res;
+ break;
+ }
+ }
+
+ switch (muxb)
+ {
+ case 0:
+ {
+ alu_b = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_b = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_b = mul_res;
+ break;
+ }
+ }
+
+ // For carry detection apparently
+ alu_a &= 0x00fffff;
+ alu_b &= 0x00fffff;
+
+ switch (alu_op)
+ {
+ case 0: // _TRA
+ {
+ alu_res = alu_a;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 1: // _NEG
+ {
+ alu_res = -alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 2: // _+
+ {
+ alu_res = alu_a + alu_b;
+ m_core->m_flag_over = (((alu_a & 0x80000) == (alu_b & 0x80000) && (alu_a & 0x80000) != (alu_res & 0x80000)));
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 3: // _+C
+ {
+ alu_res = alu_a + (m_core->m_flag_carry << 4);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 4: // _-
+ {
+ alu_res = alu_a - alu_b;
+ m_core->m_flag_over = ((alu_a & 0x80000) == (~alu_b & 0x80000) && (alu_a & 0x80000) != (alu_res & 0x80000));
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 5: // _-B
+ {
+ alu_res = alu_a - (m_core->m_flag_carry << 4);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 6: // _++
+ {
+ alu_res = alu_a + 1;
+ m_core->m_flag_over = !(alu_a & 0x80000) && (alu_res & 0x80000);
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 7: // _--
+ {
+ alu_res = alu_a - 1;
+ m_core->m_flag_over = (alu_a & 0x80000) && !(alu_res & 0x80000);
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 8: // _TRL
+ {
+ alu_res = alu_a;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 9: // _NOT
+ {
+ alu_res = ~alu_a;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 10: // _AND
+ {
+ alu_res = alu_a & alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 11: // _NAND
+ {
+ alu_res = ~(alu_a & alu_b);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 12: // _OR
+ {
+ alu_res = alu_a | alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 13: // _NOR
+ {
+ alu_res = ~(alu_a | alu_b);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 14: // _XOR
+ {
+ alu_res = alu_a ^ alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 15: // _XNOR
+ {
+ alu_res = ~(alu_a ^ alu_b);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ }
+
+ m_core->m_flag_neg = (alu_res & 0x00080000) != 0;
+ m_core->m_flag_zero = (alu_res & 0x000ffff0) == 0;
+ m_core->m_flag_exact = (alu_res & 0x0000000f) == 0;
+
+ // Barrel shift
+ static const int32_t shifts[8] = { 0, 1, 2, 3, 4, 5, 8, 16 };
+
+ if (barrel_code == 8)
+ barrel_code = read_next_operand();
+
+ if (barrel_code & 8)
+ {
+ // Right shift
+ uint32_t shift = shifts[(~barrel_code + 1) & 7];
+
+ if (alu_op < 8)
+ {
+ // Arithmetic
+ m_core->m_acc = sign_extend20(alu_res) >> shift;
+ }
+ else
+ {
+ // Logical
+ m_core->m_acc = (alu_res & 0xfffff) >> shift;
+ }
+
+ }
+ else
+ {
+ // Left shift
+ uint32_t shift = shifts[barrel_code];
+
+ if (shift == 16)
+ {
+ // Clip and saturate
+ if (m_core->m_flag_over)
+ m_core->m_acc = m_core->m_flag_neg ? 0x7ffff : 0xfff80000;
+ else
+ m_core->m_acc = sign_extend20(alu_res);
+ }
+ else
+ {
+ m_core->m_acc = sign_extend20(alu_res) << shift;
+ }
+ }
+
+ if (m_core->m_writeback >= 0)
+ {
+ write_data(m_core->m_writeback, m_core->m_acc >> 4);
+ m_core->m_writeback = -1;
+ }
+ else if (m_core->m_opidx < numops)
+ {
+ write_next_operand(m_core->m_acc >> 4);
+ }
+}
+
+
+
+//**************************************************************************
+// FIFO DMA
+//**************************************************************************
+
+//-------------------------------------------------
+// write_dma_to_fifo -
+//-------------------------------------------------
+
+void dspp_device::write_dma_to_fifo(int32_t channel, int16_t value)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ dma.m_fifo[dma.m_dma_ptr] = value;
+
+ if (dma.m_depth < DMA_FIFO_DEPTH)
+ {
+ dma.m_dma_ptr = (dma.m_dma_ptr + 1) & DMA_FIFO_MASK;
+ dma.m_depth += 1;
+ }
+ else
+ {
+ fatalerror("DMA TO FIFO OVERFLOW");
+ }
+}
+
+
+//-------------------------------------------------
+// write_dspp_to_fifo -
+//-------------------------------------------------
+
+void dspp_device::write_dspp_to_fifo(int32_t channel, int16_t value)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ dma.m_fifo[dma.m_dspi_ptr] = value;
+
+ if (dma.m_depth < DMA_FIFO_DEPTH)
+ {
+ dma.m_dspi_ptr = (dma.m_dspi_ptr + 1) & DMA_FIFO_MASK;
+ dma.m_depth += 1;
+ }
+ else
+ {
+ fatalerror("DSPP TO FIFO OVERFLOW");
+ }
+}
+
+
+//-------------------------------------------------
+// read_fifo_to_dspp -
+//-------------------------------------------------
+
+int16_t dspp_device::read_fifo_to_dspp(int32_t channel)
+{
+ int16_t data = 0;
+
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (dma.m_depth > 0)
+ {
+ data = dma.m_fifo[dma.m_dspi_ptr];
+
+ dma.m_dspi_ptr = (dma.m_dspi_ptr + 1) & DMA_FIFO_MASK;
+ --dma.m_depth;
+
+ if (dma.m_depth == 0)
+ {
+ // Set consumed interrupt
+ if (m_dspx_channel_complete & (1 << channel))
+ {
+ m_dspx_consumed_int |= 1 << channel;
+ update_host_interrupt();
+ }
+ }
+
+ dma.m_prev_current = data;
+ }
+ else
+ {
+ // TODO: Is this right?
+ m_dspx_underover_int |= 1 << channel;
+ update_host_interrupt();
+ data = dma.m_prev_current;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// read_fifo_to_dma -
+//-------------------------------------------------
+
+int16_t dspp_device::read_fifo_to_dma(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ uint32_t data = dma.m_fifo[dma.m_dma_ptr];
+
+ if (dma.m_depth > 0)
+ {
+ dma.m_dma_ptr = (dma.m_dma_ptr + 1) & DMA_FIFO_MASK;
+ dma.m_depth -= 1;
+ }
+ else
+ {
+ //fatalerror("FIFO TO DMA UNDERFLOW");
+ }
+ return data;
+}
+
+
+//-------------------------------------------------
+// run_oscillator -
+//-------------------------------------------------
+
+void dspp_device::run_oscillator(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ // Add phase increment
+ m_osc_phase += m_osc_freq;
+
+ // Extract two high bits to advance FIFO
+ uint32_t count = (m_osc_phase >> 15) & 3;
+
+ // Clip to positive phase
+ m_osc_phase &= 0x7fff;
+
+ // Advance FIFO if data present
+ if (count > dma.m_depth)
+ count = dma.m_depth;
+
+ for (uint32_t i = 0; i < count; ++i)
+ read_fifo_to_dspp(channel);
+
+ // Return count to program for counting samples
+ m_last_osc_count = count;
+}
+
+
+//-------------------------------------------------
+// advance_audio_timer -
+//-------------------------------------------------
+
+void dspp_device::advance_audio_timer()
+{
+ // Advance time on each frame count
+ ++m_dspx_audio_time;
+
+ // Interrupt on transition from 0 to 0xFFFF
+ if (--m_dspx_audio_duration == 0xffff)
+ {
+ m_core->m_partial_int |= DSPX_F_INT_TIMER;
+ update_host_interrupt();
+ }
+}
+
+
+//-------------------------------------------------
+// advance_audio_frame -
+//-------------------------------------------------
+
+void dspp_device::advance_audio_frame()
+{
+ m_last_frame_clock = m_clock;
+ advance_audio_timer();
+
+ if (m_core->m_flag_audlock)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// process_next_dma -
+//-------------------------------------------------
+
+void dspp_device::process_next_dma(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (dma.m_current_count <= 0)
+ {
+ uint32_t chmask = 1 << channel;
+
+ if (dma.m_next_valid)
+ {
+ dma.m_current_addr = dma.m_next_addr;
+ dma.m_current_count = dma.m_next_count;
+
+ if (!dma.m_go_forever)
+ dma.m_next_valid = 0;
+
+ // Set completion bit
+ m_dspx_channel_complete &= ~chmask;
+ m_dspx_dmanext_int |= chmask;
+ update_host_interrupt();
+ }
+ else
+ {
+ // Disable the channel so we don't keep servicing it
+ m_dspx_channel_enable &= ~chmask;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// decode_sqxd - Decompress an SQXD coded sample
+//-------------------------------------------------
+
+int16_t dspp_device::decode_sqxd(int8_t data, int16_t prev)
+{
+ int16_t temp = sign_extend8(data & 0xfe);
+ int32_t expanded = (temp * abs(temp)) << 1;
+ int16_t output;
+
+ if (data & 1)
+ {
+ expanded = expanded >> 2;
+ output = expanded + prev;
+ }
+ else
+ {
+ output = expanded;
+ }
+
+ return output;
+}
+
+
+//-------------------------------------------------
+// service_output_dma -
+//-------------------------------------------------
+
+void dspp_device::service_output_dma(int32_t channel)
+{
+ fifo_dma & dma = m_fifo_dma[channel];
+
+ if (dma.m_current_count == 0)
+ return;
+
+ // Transfer a maximum of 4 samples per tick
+ uint32_t count = dma.m_current_count;
+
+ if (count > 4)
+ count = 4;
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ uint16_t sample = read_fifo_to_dma(channel);
+
+ m_dma_write_handler(dma.m_current_addr++, sample >> 8);
+ m_dma_write_handler(dma.m_current_addr++, sample & 0xff);
+ }
+
+ dma.m_current_count -= count;
+
+ process_next_dma(channel);
+}
+
+
+//-------------------------------------------------
+// service_input_dma -
+//-------------------------------------------------
+
+void dspp_device::service_input_dma(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (dma.m_current_count == 0)
+ return;
+
+ // Transfer a maximum of 4 samples per tick
+ uint32_t count = dma.m_current_count;
+
+ if (count > 4)
+ count = 4;
+
+ // Determine sample format
+ bool is8bit = (m_dspx_channel_8bit & (1 << channel)) != 0;
+ bool isSQXD = (m_dspx_channel_sqxd & (1 << channel)) != 0;
+
+ if (is8bit)
+ {
+ // Fetch data from memory, {decompress}, and write to FIFO
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ int16_t sample;
+ int8_t curbyte = m_dma_read_handler(dma.m_current_addr++);
+
+ if (isSQXD)
+ {
+ printf("SQXD NOT TESTED!");
+
+ sample = decode_sqxd(curbyte, dma.m_prev_value);
+ dma.m_prev_value = sample;
+ }
+ else
+ {
+ sample = curbyte << 8;
+ }
+
+ write_dma_to_fifo(channel, sample);
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ int16_t sample;
+
+ sample = m_dma_read_handler(dma.m_current_addr++) << 8;
+ sample |= m_dma_read_handler(dma.m_current_addr++);
+
+ write_dma_to_fifo(channel, sample);
+ }
+ }
+
+ dma.m_current_count -= count;
+
+ process_next_dma(channel);
+}
+
+
+//-------------------------------------------------
+// update_fifo_dma -
+//-------------------------------------------------
+
+void dspp_device::update_fifo_dma()
+{
+ uint32_t mask = m_dspx_channel_enable & ~m_dspx_channel_complete;
+
+ while (mask != 0)
+ {
+ uint32_t channel = 31 - count_leading_zeros(mask);
+
+ const fifo_dma & dma = m_fifo_dma[channel];
+
+ if (m_dspx_channel_direction & (1 << channel))
+ {
+ if (dma.m_depth >= 4)
+ {
+ service_output_dma(channel);
+ break;
+ }
+ }
+ else
+ {
+ if (dma.m_depth <= 4)
+ {
+ service_input_dma(channel);
+ break;
+ }
+ }
+
+ mask &= (1 << channel) - 1;
+ }
+}
+
+
+//-------------------------------------------------
+// reset_channel
+//-------------------------------------------------
+
+void dspp_device::reset_channel(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ m_dspx_channel_complete &= ~(1 << channel);
+
+ dma.m_dma_ptr = 0;
+ dma.m_dspi_ptr = 0;
+ dma.m_depth = 0;
+}
+
+
+
+//**************************************************************************
+// INTERNAL REGISTERS
+//**************************************************************************
+
+//-------------------------------------------------
+// input_r - Read digital input
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::input_r )
+{
+ // TODO
+ return 0;
+}
+
+
+//-------------------------------------------------
+// output_w - Write to the 8 output registers
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::output_w )
+{
+ m_outputs[offset] = data;
+}
+
+
+//-------------------------------------------------
+// fifo_osc_r -
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::fifo_osc_r )
+{
+ uint32_t data = 0;
+ uint32_t channel = offset / 8;
+
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ switch (offset & 7)
+ {
+ // DSPI_FIFO_OSC_OFFSET_CURRENT
+ case 0:
+ {
+ if (dma.m_depth == 0)
+ data = dma.m_prev_current;
+ else
+ data = dma.m_fifo[dma.m_dspi_ptr];
+
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_NEXT
+ case 1:
+ {
+ if (dma.m_depth == 0)
+ data = dma.m_prev_current;
+ else if (dma.m_depth == 1)
+ data = dma.m_fifo[dma.m_dspi_ptr];
+ else
+ data = dma.m_fifo[(dma.m_dspi_ptr + 1) & DMA_FIFO_MASK];
+
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_FREQUENCY
+ case 2:
+ {
+ data = m_last_osc_count;
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_PHASE
+ case 3:
+ {
+ data = m_osc_phase;
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_DATA
+ case 4:
+ {
+ data = read_fifo_to_dspp(channel);
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_CONTROL
+ case 5:
+ {
+ data = dma.m_depth;
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// fifo_osc_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::fifo_osc_w )
+{
+ uint32_t channel = offset / 8;
+
+ switch (offset & 7)
+ {
+ // DSPI_FIFO_OSC_OFFSET_CURRENT
+ case 0:
+ {
+ // Read only
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_NEXT
+ case 1:
+ {
+ // Read only
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_FREQUENCY
+ case 2:
+ {
+ m_osc_freq = data;
+ run_oscillator(channel);
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_PHASE
+ case 3:
+ {
+ m_osc_phase = data;
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_DATA
+ case 4:
+ {
+ write_dspp_to_fifo(channel, data);
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_CONTROL
+ case 5:
+ {
+ // Read only
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// input_control_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::input_control_w )
+{
+ // TODO
+}
+
+
+//-------------------------------------------------
+// output_control_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::output_control_w )
+{
+ // TODO
+ if (data & 1)
+ {
+ uint32_t end;
+
+ if (m_output_fifo_count == OUTPUT_FIFO_DEPTH)
+ {
+ // Overflow
+ end = (m_output_fifo_start + m_output_fifo_count) & OUTPUT_FIFO_MASK;
+
+ m_output_fifo_start = (m_output_fifo_start + 2) & OUTPUT_FIFO_MASK;
+
+ m_output_fifo[(end + 0) & OUTPUT_FIFO_MASK] = m_outputs[0];
+ m_output_fifo[(end + 1) & OUTPUT_FIFO_MASK] = m_outputs[1];
+ }
+ else
+ {
+ end = (m_output_fifo_start + m_output_fifo_count) & OUTPUT_FIFO_MASK;
+
+ m_output_fifo[(end + 0) & OUTPUT_FIFO_MASK] = m_outputs[0];
+ m_output_fifo[(end + 1) & OUTPUT_FIFO_MASK] = m_outputs[1];
+
+ // Advance and update FIFO status
+ m_output_fifo_count += 2;
+ }
+
+ advance_audio_frame();
+ }
+}
+
+
+//-------------------------------------------------
+// input_status_r - Read input state
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::input_status_r )
+{
+ // TODO: How should this work?
+ return 1;
+}
+
+
+//-------------------------------------------------
+// output_status_r - Return number of unread
+// entries in the output FIFO
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::output_status_r )
+{
+ return m_output_fifo_count;
+}
+
+
+//-------------------------------------------------
+// cpu_int_w - Host CPU soft interrupt
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::cpu_int_w )
+{
+ m_core->m_partial_int |= (data << DSPX_FLD_INT_SOFT_SHIFT) & DSPX_FLD_INT_SOFT_MASK;
+ update_host_interrupt();
+}
+
+
+//-------------------------------------------------
+// pc_r - Read program counter
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::pc_r )
+{
+ return m_core->m_pc;
+}
+
+
+//-------------------------------------------------
+// pc_w - Write program counter
+//-------------------------------------------------
+
+WRITE16_MEMBER(dspp_device:: pc_w )
+{
+ m_core->m_pc = data;
+}
+
+
+//-------------------------------------------------
+// audlock_r - Read Audio Lock status
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::audlock_r )
+{
+ return m_core->m_flag_audlock;
+}
+
+
+//-------------------------------------------------
+// audlock_w - Write Audio Lock status
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::audlock_w )
+{
+ m_core->m_flag_audlock = data & 1;
+}
+
+
+//-------------------------------------------------
+// clock_r - Read CPU tick counter
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::clock_r )
+{
+ return m_core->m_tclock;
+}
+
+
+//-------------------------------------------------
+// clock_w - Write CPU tick counter
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::clock_w )
+{
+ m_core->m_tclock = data;
+}
+
+
+//-------------------------------------------------
+// noise_r - PRNG noise
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::noise_r )
+{
+ // TODO: Obviously this isn't accurate
+ return machine().rand();
+}
+
+
+
+//**************************************************************************
+// EXTERNAL INTERFACE AND CONTROL REGISTERS
+//**************************************************************************
+
+//-------------------------------------------------
+// read_ext_control -
+//-------------------------------------------------
+
+uint32_t dspp_device::read_ext_control(offs_t offset)
+{
+ uint32_t data = 0;
+
+ switch (offset)
+ {
+ // DSPX_INTERRUPT_SET
+ case 0x4000/4:
+ // DSPX_INTERRUPT_CLR
+ case 0x4004/4:
+ {
+ data = get_interrupt_state();
+ break;
+ }
+
+ // DSPX_INTERRUPT_ENABLE
+ case 0x4008/4:
+ // DSPX_INTERRUPT_DISABLE
+ case 0x400C/4:
+ {
+ data = m_dspx_int_enable;
+ break;
+ }
+ // DSPX_INT_DMANEXT_SET
+ case 0x4010/4:
+ // DSPX_INT_DMANEXT_CLR
+ case 0x4014/4:
+ {
+ data = m_dspx_dmanext_int;
+ break;
+ }
+ // DSPX_INT_DMANEXT_ENABLE
+ case 0x4018/4:
+ {
+ data = m_dspx_dmanext_enable;
+ break;
+ }
+ // DSPX_INT_CONSUMED_SET
+ case 0x4020/4:
+ // DSPX_INT_CONSUMED_CLR
+ case 0x4024/4:
+ {
+ data = m_dspx_consumed_int;
+ break;
+ }
+ // DSPX_INT_CONSUMED_ENABLE
+ case 0x4028/4:
+ // DSPX_INT_CONSUMED_DISABLE
+ case 0x402c/4:
+ {
+ data = m_dspx_consumed_enable;
+ break;
+ }
+
+ // DSPX_INT_UNDEROVER_SET
+ case 0x4030/4:
+ // DSPX_INT_UNDEROVER_CLR
+ case 0x4034/4:
+ {
+ data = m_dspx_underover_int;
+ break;
+ }
+
+ // DSPX_INT_UNDEROVER_ENABLE
+ case 0x4038/4:
+ // DSPX_INT_UNDEROVER_DISABLE
+ case 0x403c/4:
+ {
+ data = m_dspx_underover_enable;
+ break;
+ }
+
+ // DSPX_CHANNEL_ENABLE
+ case 0x6000/4:
+ // DSPX_CHANNEL_DISABLE
+ case 0x6004/4:
+ {
+ data = m_dspx_channel_enable;
+ break;
+ }
+ // DSPX_CHANNEL_DIRECTION_SET
+ case 0x6008/4:
+ // DSPX_CHANNEL_DIRECTION_CLR
+ case 0x600c/4:
+ {
+ data = m_dspx_channel_direction;
+ break;
+ }
+ // DSPX_CHANNEL_8BIT_SET
+ case 0x6010/4:
+ // DSPX_CHANNEL_8BIT_CLR
+ case 0x6014/4:
+ {
+ data = m_dspx_channel_8bit;
+ break;
+ }
+ // DSPX_CHANNEL_SQXD_SET
+ case 0x6018/4:
+ // DSPX_CHANNEL_SQXD_CLR
+ case 0x601c/4:
+ {
+ data = m_dspx_channel_sqxd;
+ break;
+ }
+ // DSPX_CHANNEL_STATUS
+ case 0x603c/4:
+ {
+ data = m_dspx_channel_complete;
+ break;
+ }
+
+ // DSPX_FRAME_DOWN_COUNTER:
+ case 0x6040/4:
+ {
+ data = m_dspx_audio_duration;
+ break;
+ }
+ // DSPX_FRAME_UP_COUNTER:
+ case 0x6044/4:
+ {
+ data = m_dspx_audio_time;
+ break;
+ }
+
+ // AUDIO_CONFIG
+ case 0x6050/4:
+ {
+ break;
+ }
+ // AUDIN_CONFIG
+ case 0x6060/4:
+ {
+ break;
+ }
+ // AUDOUT_CONFIG
+ case 0x6068/4:
+ {
+ break;
+ }
+ // DSPX_CONTROL
+ case 0x6070/4:
+ {
+ data = m_dspx_control;
+ break;
+ }
+ default:
+ {
+ printf("DSPP: Unhandled external control read (%.4x)\n", offset << 2);
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_ext_control -
+//-------------------------------------------------
+
+void dspp_device::write_ext_control(offs_t offset, uint32_t data)
+{
+ switch (offset)
+ {
+ // DSPX_INTERRUPT_SET
+ case 0x4000/4:
+ {
+ m_core->m_partial_int |= data & ~DSPX_F_INT_ALL_DMA;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INTERRUPT_CLR
+ case 0x4004/4:
+ {
+ m_core->m_partial_int &= ~(data & ~DSPX_F_INT_ALL_DMA);
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INTERRUPT_ENABLE
+ case 0x4008/4:
+ {
+ m_dspx_int_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INTERRUPT_DISABLE
+ case 0x400C/4:
+ {
+ m_dspx_int_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_DMANEXT_SET
+ case 0x4010/4:
+ {
+ m_dspx_dmanext_int |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_DMANEXT_CLR
+ case 0x4014/4:
+ {
+ m_dspx_dmanext_int &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_DMANEXT_ENABLE
+ case 0x4018/4:
+ {
+ m_dspx_dmanext_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_SET
+ case 0x4020/4:
+ {
+ m_dspx_consumed_int |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_CLR
+ case 0x4024/4:
+ {
+ m_dspx_consumed_int &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_ENABLE
+ case 0x4028/4:
+ {
+ m_dspx_consumed_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_DISABLE
+ case 0x402c/4:
+ {
+ m_dspx_consumed_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+
+ // DSPX_INT_UNDEROVER_SET
+ case 0x4030/4:
+ {
+ m_dspx_underover_int |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_UNDEROVER_CLR
+ case 0x4034/4:
+ {
+ m_dspx_underover_int &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_UNDEROVER_ENABLE
+ case 0x4038/4:
+ {
+ m_dspx_underover_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_UNDEROVER_DISABLE
+ case 0x403c/4:
+ {
+ m_dspx_underover_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+
+ // DSPX_CHANNEL_ENABLE
+ case 0x6000/4:
+ {
+ m_dspx_channel_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_CHANNEL_DISABLE
+ case 0x6004/4:
+ {
+ m_dspx_channel_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_CHANNEL_DIRECTION_SET
+ case 0x6008/4:
+ {
+ m_dspx_channel_direction |= data;
+ break;
+ }
+ // DSPX_CHANNEL_DIRECTION_CLR
+ case 0x600c/4:
+ {
+ m_dspx_channel_direction &= ~data;
+ break;
+ }
+ // DSPX_CHANNEL_8BIT_SET
+ case 0x6010/4:
+ {
+ m_dspx_channel_8bit |= data;
+ break;
+ }
+ // DSPX_CHANNEL_8BIT_CLR
+ case 0x6014/4:
+ {
+ m_dspx_channel_8bit &= ~data;
+ break;
+ }
+ // DSPX_CHANNEL_SQXD_SET
+ case 0x6018/4:
+ {
+ m_dspx_channel_sqxd |= data;
+ break;
+ }
+ // DSPX_CHANNEL_SQXD_CLR
+ case 0x601c/4:
+ {
+ m_dspx_channel_sqxd &= ~data;
+ break;
+ }
+ // DSPX_CHANNEL_RESET
+ case 0x6030/4:
+ {
+ for (uint32_t i = 0; i < NUM_DMA_CHANNELS; ++i)
+ {
+ if (data & (1 << i))
+ reset_channel(i);
+ }
+ break;
+ }
+
+ // DSPX_FRAME_DOWN_COUNTER:
+ case 0x6040/4:
+ {
+ m_dspx_audio_duration = data;
+ break;
+ }
+ // DSPX_FRAME_UP_COUNTER:
+ case 0x6044/4:
+ {
+ m_dspx_audio_time = data;
+ break;
+ }
+
+ // AUDIO_CONFIG
+ case 0x6050/4:
+ {
+ break;
+ }
+
+ // AUDIN_CONFIG
+ case 0x6060/4:
+ {
+ break;
+ }
+
+ // AUDOUT_CONFIG
+ case 0x6068/4:
+ {
+ break;
+ }
+
+ // DSPX_CONTROL
+ case 0x6070/4:
+ {
+ m_dspx_control = data;
+ break;
+ }
+
+ // DSPX_RESET
+ case 0x6074/4:
+ {
+ if (data & 1)
+ device_reset();
+
+ // TODO: DSPX_F_RESET_INPUT and DSPX_F_RESET_OUTPUT
+
+ break;
+ }
+ default:
+ {
+ printf("DSPP: Unhandled external control write (%.4x with %.8x)\n", offset << 2, data);
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// read - host CPU read from DSPP internals
+//-------------------------------------------------
+
+READ32_MEMBER( dspp_device::read )
+{
+ if (offset < 0x1000/4)
+ {
+ // 16-bit code memory
+ return m_code->read_word(offset);
+ }
+ else if (offset >= 0x1000/4 && offset < 0x2000/4)
+ {
+ // 16-bit data memory and registers
+ return m_data->read_word((offset - 0x1000/4));
+ }
+ else if(offset >= 0x5000/4 && offset < 0x6000/4)
+ {
+ // DMA registers
+ return read_dma_stack(offset - 0x5000/4);
+ }
+ else
+ {
+ // 32-bit control registers
+ return read_ext_control(offset);
+ }
+}
+
+
+//-------------------------------------------------
+// read_dma_stack -
+//-------------------------------------------------
+
+uint32_t dspp_device::read_dma_stack(offs_t offset)
+{
+ uint32_t data = 0;
+
+ if (offset < 0x200 / 4)
+ {
+ uint32_t channel = offset / (16/4);
+ uint32_t reg = offset & 3;
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ switch (reg)
+ {
+ case 0x00/4://DSPX_DMA_ADDR_OFFSET:
+ {
+ data = dma.m_current_addr;
+ break;
+ }
+ case 0x04/4://DSPX_DMA_COUNT_OFFSET:
+ {
+ data = dma.m_current_count;
+ break;
+ }
+ case 0x08/4://DSPX_DMA_NEXT_ADDR_OFFSET:
+ {
+ data = dma.m_next_addr;
+ break;
+ }
+ case 0x0c/4://DSPX_DMA_NEXT_COUNT_OFFSET:
+ {
+ data = dma.m_next_count;
+ break;
+ }
+ }
+ }
+ else if (offset >= 0x200/4 && offset < (0x200/4 + (NUM_DMA_CHANNELS * (16/4))))
+ {
+ uint32_t channel = (offset - 0x200/4) / (16/4);
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ data = dma.m_go_forever ? DSPX_F_DMA_GO_FOREVER : 0;
+ data |= dma.m_next_valid ? DSPX_F_DMA_NEXTVALID : 0;
+ }
+ else
+ {
+ fatalerror("Unhandled DMA stack read");
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_dma_stack -
+//-------------------------------------------------
+
+void dspp_device::write_dma_stack(offs_t offset, uint32_t data)
+{
+ if (offset < 0x200 / 4)
+ {
+ switch (offset & 3)
+ {
+ case 0x00/4://DSPX_DMA_ADDR_OFFSET:
+ {
+ m_dspx_shadow_current_addr = data;
+ break;
+ }
+ case 0x04/4://DSPX_DMA_COUNT_OFFSET:
+ {
+ m_dspx_shadow_current_count = data;
+ break;
+ }
+ case 0x08/4://DSPX_DMA_NEXT_ADDR_OFFSET:
+ {
+ m_dspx_shadow_next_addr = data;
+ break;
+ }
+ case 0x0c/4://DSPX_DMA_NEXT_COUNT_OFFSET:
+ {
+ m_dspx_shadow_next_count = data;
+ break;
+ }
+ }
+ }
+ else if (offset >= 0x200/4 && offset < (0x200/4 + (NUM_DMA_CHANNELS * (16/4))))
+ {
+ uint32_t channel = (offset - 0x200/4) / (16/4);
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (data & DSPX_F_SHADOW_SET_NEXTVALID)
+ {
+ dma.m_next_valid = (data & DSPX_F_DMA_NEXTVALID) != 0;
+ }
+ if (data & DSPX_F_SHADOW_SET_FOREVER)
+ {
+ dma.m_go_forever = (data & DSPX_F_DMA_GO_FOREVER) != 0;
+ }
+ if (data & DSPX_F_SHADOW_SET_DMANEXT)
+ {
+ if (data & DSPX_F_INT_DMANEXT_EN)
+ {
+ m_dspx_dmanext_enable |= (1 << channel);
+ }
+ else
+ {
+ m_dspx_dmanext_enable &= ~(1 << channel);
+ }
+ }
+ if (data & DSPX_F_SHADOW_SET_ADDRESS_COUNT)
+ {
+ if (offset & (8/4))
+ {
+ dma.m_next_addr = m_dspx_shadow_next_addr;
+ dma.m_next_count = m_dspx_shadow_next_count;
+ }
+ else
+ {
+ dma.m_current_addr = m_dspx_shadow_current_addr;
+ dma.m_current_count = m_dspx_shadow_current_count;
+ }
+ }
+ }
+ else
+ {
+ fatalerror("Unhandled DMA stack write");
+ }
+}
+
+
+//-------------------------------------------------
+// write - host CPU write to DSPP internals
+//-------------------------------------------------
+
+WRITE32_MEMBER( dspp_device::write )
+{
+ if (offset < 0x1000/4)
+ {
+ // 16-bit code memory
+ m_code->write_word(offset, data);
+ }
+ else if (offset >= 0x1000/4 && offset < 0x2000/4)
+ {
+ // 16-bit data memory and registers
+ m_data->write_word((offset - 0x1000/4), data);
+ }
+ else if(offset >= 0x5000/4 && offset < 0x6000/4)
+ {
+ // DMA registers
+ write_dma_stack(offset - 0x5000/4, data);
+
+ // Better safe than sorry...
+ machine().scheduler().synchronize();
+ }
+ else
+ {
+ // 32-bit control registers
+ write_ext_control(offset, data);
+
+ // Better safe than sorry...
+ machine().scheduler().synchronize();
+ }
+}
+
+
+//-------------------------------------------------
+// read_output_fifo - Get data for the DACs
+//-------------------------------------------------
+
+uint16_t dspp_device::read_output_fifo()
+{
+ uint16_t data = 0;
+
+ if (m_output_fifo_count == 0)
+ {
+ // Underflow
+ return m_output_fifo[m_output_fifo_start];
+ }
+
+ data = m_output_fifo[m_output_fifo_start];
+
+ m_output_fifo_start = (m_output_fifo_start + 1) & OUTPUT_FIFO_MASK;
+ --m_output_fifo_count;
+
+ return data;
+}
+
+// DEBUG!
+
+char * GetBinary(char * buffer, uint32_t val, uint32_t bits)
+{
+ uint32_t i;
+
+ for (i = 0; i < bits; ++i)
+ buffer[i] = (val >> (bits - 1 - i)) & 1 ? '1' : '0';
+
+ buffer[i] = '\0';
+
+ return buffer;
+}
+
+void dspp_device::dump_state()
+{
+ // DMA
+ for (uint32_t i = 0; i < NUM_DMA_CHANNELS; ++i)
+ {
+ printf("\n=== CHANNEL %02X ===\n", i);
+ printf("CURR_ADDRESS: %08X\n", m_fifo_dma[i].m_current_addr);
+ printf("CURR_COUNT: %08X\n", m_fifo_dma[i].m_current_count);
+ printf("NEXT_ADDR: %08X\n", m_fifo_dma[i].m_next_addr);
+ printf("NEXT_COUNT: %08X\n", m_fifo_dma[i].m_next_count);
+ printf("PREV_VALUE: %08X\n", m_fifo_dma[i].m_prev_value);
+ printf("PREV_CURRENT: %08X\n", m_fifo_dma[i].m_prev_current);
+ printf("GO_FOREVER: %X\n", m_fifo_dma[i].m_go_forever);
+ printf("NEXT_VALID: %X\n", m_fifo_dma[i].m_next_valid);
+ }
+
+ char buffer[64];
+
+ printf("\n=== GLOBAL REGISTER===\n");
+ printf("DSPX_CONTROL: %08X\n", m_dspx_control);
+ printf("DSPX_RESET: %08X\n", m_dspx_reset);
+ printf("DSPX_INT_ENABLE: %08X\n", m_dspx_int_enable);
+ printf("DSPX_CHANNEL_ENABLE: %08X %s\n", m_dspx_channel_enable, GetBinary(buffer, m_dspx_channel_enable, 32));
+ printf("DSPX_CHANNEL_COMPLETE: %08X %s\n", m_dspx_channel_complete, GetBinary(buffer, m_dspx_channel_complete, 32));
+ printf("DSPX_CHANNEL_DIRECTION: %08X %s\n", m_dspx_channel_direction, GetBinary(buffer, m_dspx_channel_direction, 32));
+ printf("DSPX_CHANNEL_8BIT: %08X %s\n", m_dspx_channel_8bit, GetBinary(buffer, m_dspx_channel_8bit, 32));
+ printf("DSPX_CHANNEL_SQXD: %08X %s\n", m_dspx_channel_sqxd, GetBinary(buffer, m_dspx_channel_sqxd, 32));
+
+#if 0
+ uint32_t m_dspx_shadow_current_addr;
+ uint32_t m_dspx_shadow_current_count;
+ uint32_t m_dspx_shadow_next_addr;
+ uint32_t m_dspx_shadow_next_count;
+ uint32_t m_dspx_dmanext_int;
+ uint32_t m_dspx_dmanext_enable;
+ uint32_t m_dspx_consumed_int;
+ uint32_t m_dspx_consumed_enable;
+ uint32_t m_dspx_underover_int;
+ uint32_t m_dspx_underover_enable;
+ uint32_t m_dspx_audio_time;
+ uint16_t m_dspx_audio_duration;
+#endif
+}
diff --git a/src/devices/cpu/dspp/dspp.h b/src/devices/cpu/dspp/dspp.h
new file mode 100644
index 00000000000..848c2931714
--- /dev/null
+++ b/src/devices/cpu/dspp/dspp.h
@@ -0,0 +1,337 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dspp.h
+
+ Core implementation for the portable DSPP emulator.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __DSPP_H__
+#define __DSPP_H__
+
+#include "cpu/drcfe.h"
+#include "cpu/drcuml.h"
+#include "cpu/drcumlsh.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class dspp_frontend;
+
+// ======================> dspp_device
+
+class dspp_device : public cpu_device
+{
+ friend class dspp_frontend;
+public:
+ // Construction/destruction
+ dspp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor code_map_ctor,
+ address_map_constructor data_map_ctor);
+ dspp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Static configuration helpers
+ auto int_handler() { return m_int_handler.bind(); }
+ auto dma_read_handler() { return m_dma_read_handler.bind(); }
+ auto dma_write_handler() { return m_dma_write_handler.bind(); }
+
+ // Public interfaces
+ DECLARE_READ32_MEMBER( read );
+ DECLARE_WRITE32_MEMBER( write );
+
+ uint16_t read_output_fifo();
+
+ void dump_state(); // TODO: DEBUG REMOVE ME
+
+ // Internal registers
+ DECLARE_READ16_MEMBER( input_r );
+ DECLARE_WRITE16_MEMBER( output_w );
+ DECLARE_READ16_MEMBER( fifo_osc_r );
+ DECLARE_WRITE16_MEMBER( fifo_osc_w );
+ DECLARE_WRITE16_MEMBER( input_control_w );
+ DECLARE_WRITE16_MEMBER( output_control_w );
+ DECLARE_READ16_MEMBER( input_status_r );
+ DECLARE_READ16_MEMBER( output_status_r );
+ DECLARE_WRITE16_MEMBER( cpu_int_w );
+ DECLARE_READ16_MEMBER( pc_r );
+ DECLARE_WRITE16_MEMBER( pc_w );
+ DECLARE_READ16_MEMBER( audlock_r );
+ DECLARE_WRITE16_MEMBER( audlock_w );
+ DECLARE_READ16_MEMBER( clock_r );
+ DECLARE_WRITE16_MEMBER( clock_w );
+ DECLARE_READ16_MEMBER( noise_r );
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_execute_interface overrides
+ virtual uint32_t execute_min_cycles() const override;
+ virtual uint32_t execute_max_cycles() const override;
+ virtual void execute_run() override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_state_interface overrides
+ virtual void state_import(const device_state_entry &entry) override;
+ virtual void state_export(const device_state_entry &entry) override;
+ virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+
+ // device_disasm_interface overrides
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+
+ void code_map(address_map &map);
+ void data_map(address_map &map);
+
+private:
+ // Constants
+ static const uint32_t PC_STACK_DEPTH = 4;
+ static const uint32_t MAX_OPERANDS = 8;
+
+ static const uint32_t NUM_DMA_CHANNELS = 32;
+ static const uint32_t DMA_FIFO_DEPTH = 8;
+ static const uint32_t DMA_FIFO_MASK = DMA_FIFO_DEPTH - 1;
+
+ static const uint32_t NUM_INPUTS = 2;
+ static const uint32_t NUM_OUTPUTS = 8;
+ static const uint32_t OUTPUT_FIFO_DEPTH = 8;
+ static const uint32_t OUTPUT_FIFO_MASK = OUTPUT_FIFO_DEPTH - 1;
+
+ // Handlers
+ devcb_write_line m_int_handler;
+ devcb_read8 m_dma_read_handler;
+ devcb_write8 m_dma_write_handler;
+
+ // Internal functions
+ uint16_t read_op(offs_t pc);
+ inline uint16_t read_data(offs_t addr);
+ inline void write_data(offs_t addr, uint16_t data);
+
+ inline void update_pc();
+ inline void update_ticks();
+ inline void exec_control();
+ inline void exec_super_special();
+ inline void exec_special();
+ inline void exec_branch();
+ inline void exec_complex_branch();
+ inline void exec_arithmetic();
+ void parse_operands(uint32_t numops);
+ uint16_t read_next_operand();
+ void write_next_operand(uint16_t value);
+ inline void push_pc();
+ inline uint16_t pop_pc();
+ inline void set_rbase(uint32_t base, uint32_t addr);
+ inline uint16_t translate_reg(uint16_t reg);
+
+ void update_fifo_dma();
+ void process_next_dma(int32_t channel);
+ void service_input_dma(int32_t channel);
+ void service_output_dma(int32_t channel);
+ int16_t read_fifo_to_dspp(int32_t channel);
+ int16_t read_fifo_to_dma(int32_t channel);
+ void write_dma_to_fifo(int32_t channel, int16_t value);
+ void write_dspp_to_fifo(int32_t channel, int16_t value);
+
+ void run_oscillator(int32_t channel);
+ void reset_channel(int32_t channel);
+ void advance_audio_timer();
+ void advance_audio_frame();
+ int16_t decode_sqxd(int8_t val, int16_t prev);
+
+ uint32_t get_interrupt_state();
+ void update_host_interrupt();
+
+ uint32_t read_dma_stack(offs_t offset);
+ void write_dma_stack(offs_t offset, uint32_t data);
+
+ uint32_t read_ext_control(offs_t offset);
+ void write_ext_control(offs_t offset, uint32_t data);
+
+ bool m_isdrc;
+
+ // Address spaces
+ const address_space_config m_code_config;
+ const address_space_config m_data_config;
+ address_space * m_code;
+ address_space * m_data;
+ memory_access_cache<1, -1, ENDIANNESS_BIG> *m_code_cache;
+ std::function<const void * (offs_t)> m_codeptr;
+
+ struct dspp_internal_state
+ {
+ // Internal state
+ int m_icount;
+ uint16_t m_pc;
+ uint16_t m_stack[PC_STACK_DEPTH];
+ uint32_t m_stack_ptr;
+ uint16_t m_rbase[4];
+ uint32_t m_acc;
+ uint32_t m_tclock;
+
+ uint32_t m_flag_carry;
+ uint32_t m_flag_zero;
+ uint32_t m_flag_neg;
+ uint32_t m_flag_over;
+ uint32_t m_flag_exact;
+ uint32_t m_flag_audlock;
+ uint32_t m_flag_sleep;
+
+ uint32_t m_partial_int;
+ uint16_t m_op;
+ uint32_t m_opidx;
+ int32_t m_writeback;
+
+ const char *m_format;
+ uint32_t m_arg0;
+ } * m_core;
+
+ struct
+ {
+ uint32_t value;
+ uint32_t addr;
+ } m_operands[MAX_OPERANDS];
+
+ // DMA
+ struct fifo_dma
+ {
+ uint32_t m_current_addr;
+ int32_t m_current_count;
+ uint32_t m_next_addr;
+ uint32_t m_next_count;
+ uint32_t m_prev_value;
+ uint32_t m_prev_current;
+ uint8_t m_go_forever;
+ uint8_t m_next_valid;
+ uint8_t m_reserved;
+ uint16_t m_fifo[DMA_FIFO_DEPTH];
+ uint32_t m_dma_ptr;
+ uint32_t m_dspi_ptr;
+ uint32_t m_depth;
+ } m_fifo_dma[NUM_DMA_CHANNELS];
+
+ // Oscillator
+ uint32_t m_last_frame_clock;
+ uint32_t m_last_osc_count;
+ uint32_t m_osc_phase;
+ uint32_t m_osc_freq;
+
+ // Output FIFO
+ uint16_t m_outputs[NUM_OUTPUTS];
+ uint16_t m_output_fifo[OUTPUT_FIFO_DEPTH];
+ uint32_t m_output_fifo_start;
+ uint32_t m_output_fifo_count;
+
+ // External control registers
+ uint32_t m_dspx_control;
+ uint32_t m_dspx_reset;
+ uint32_t m_dspx_int_enable;
+ uint32_t m_dspx_channel_enable;
+ uint32_t m_dspx_channel_complete;
+ uint32_t m_dspx_channel_direction;
+ uint32_t m_dspx_channel_8bit;
+ uint32_t m_dspx_channel_sqxd;
+ uint32_t m_dspx_shadow_current_addr;
+ uint32_t m_dspx_shadow_current_count;
+ uint32_t m_dspx_shadow_next_addr;
+ uint32_t m_dspx_shadow_next_count;
+ uint32_t m_dspx_dmanext_int;
+ uint32_t m_dspx_dmanext_enable;
+ uint32_t m_dspx_consumed_int;
+ uint32_t m_dspx_consumed_enable;
+ uint32_t m_dspx_underover_int;
+ uint32_t m_dspx_underover_enable;
+ uint32_t m_dspx_audio_time;
+ uint16_t m_dspx_audio_duration;
+
+ //
+ // DRC
+ //
+
+ // Core state
+ /* internal stuff */
+ bool m_cache_dirty;
+ drc_cache m_cache;
+ std::unique_ptr<drcuml_state> m_drcuml;
+ std::unique_ptr<dspp_frontend> m_drcfe;
+ uint32_t m_drcoptions;
+
+ /* internal compiler state */
+ struct compiler_state
+ {
+ uint32_t cycles; /* accumulated cycles */
+ uint8_t checkints; /* need to check interrupts before next instruction */
+ uint8_t checksoftints; /* need to check software interrupts before next instruction */
+ uml::code_label labelnum; /* index for local labels */
+ };
+
+public: // TODO
+ void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name);
+ void load_fast_iregs(drcuml_block &block);
+ void save_fast_iregs(drcuml_block &block);
+// void arm7_drc_init();
+// void arm7_drc_exit();
+ void execute_run_drc();
+// void arm7drc_set_options(uint32_t options);
+// void arm7drc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base);
+// void arm7drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles);
+ void flush_cache();
+ void compile_block(offs_t pc);
+ void cfunc_get_cycles();
+ void cfunc_unimplemented();
+ void static_generate_entry_point();
+ void static_generate_nocode_handler();
+ void static_generate_out_of_cycles();
+ void static_generate_memory_accessor(int size, bool istlb, bool iswrite, const char *name, uml::code_handle **handleptr);
+ void generate_update_cycles(drcuml_block &block, compiler_state *compiler, uml::parameter param);
+ void generate_checksum_block(drcuml_block &block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast);
+ void generate_sequence_instruction(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc);
+
+ bool generate_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc);
+
+
+ /* subroutines */
+ uml::code_handle * m_entry; /* entry point */
+ uml::code_handle * m_nocode; /* nocode exception handler */
+ uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */
+};
+
+
+/***************************************************************************
+ COMPILER-SPECIFIC OPTIONS
+ ***************************************************************************/
+
+#define DSPPDRC_STRICT_VERIFY 0x0001 /* verify all instructions */
+#define DSPPDRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */
+
+#define DSPPDRC_COMPATIBLE_OPTIONS (DSPPDRC_STRICT_VERIFY | DSPPDRC_FLUSH_PC)
+#define DSPPDRC_FASTEST_OPTIONS (0)
+
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_DSPP_INT_HANDLER(_devcb) \
+ devcb = &dspp_device::set_int_handler(*device, DEVCB_##_devcb);
+
+#define MCFG_DSPP_DMA_READ_HANDLER(_devcb) \
+ devcb = &dspp_device::set_dma_read_handler(*device, DEVCB_##_devcb);
+
+#define MCFG_DSPP_DMA_WRITE_HANDLER(_devcb) \
+ devcb = &dspp_device::set_dma_write_handler(*device, DEVCB_##_devcb);
+
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(DSPP, dspp_device);
+
+
+#endif /* __DSPP_H__ */
diff --git a/src/devices/cpu/dspp/dsppdasm.cpp b/src/devices/cpu/dspp/dsppdasm.cpp
new file mode 100644
index 00000000000..6b43df5d452
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppdasm.cpp
@@ -0,0 +1,124 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dsppdasm.c
+ Disassembler for the portable DSPP emulator.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "dspp.h"
+#include "dsppdasm.h"
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+uint32_t dspp_disassembler::opcode_alignment() const
+{
+ return 2;
+}
+
+offs_t dspp_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+#if 0
+ uint32_t op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24);
+ int opcode = op >> 27;
+ int cond = (op >> 21) & 1;
+ int rdst = (op >> 22) & 31;
+ int rsrc1 = (op >> 16) & 31;
+ int rsrc2 = op & 0xffff;
+ int rsrc2_iszero = (!rsrc2 || rsrc2 == 0xffe0);
+ uint32_t flags = 0;
+
+ switch (opcode)
+ {
+ case 0x00: sprintf(buffer, "trap $00"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x01: sprintf(buffer, "b%s $%08x", condition[rdst & 15], pc + ((INT32)(op << 10) >> 8)); break;
+ case 0x02: if ((op & 0x003fffff) == 3)
+ {
+ uint32_t nextop = oprom[4] | (oprom[5] << 8) | (oprom[6] << 16) | (oprom[7] << 24);
+ if ((nextop >> 27) == 0x10 && ((nextop >> 22) & 31) == rdst && (nextop & 0xffff) == 0)
+ {
+ uint32_t nextnextop = oprom[8] | (oprom[9] << 8) | (oprom[10] << 16) | (oprom[11] << 24);
+ sprintf(buffer, "llit%s $%08x,%s", setcond[cond], nextnextop, reg[rdst]);
+ return 12 | DASMFLAG_STEP_OVER | DASMFLAG_SUPPORTED;
+ }
+ }
+ if (rdst)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "bsr %s,$%08x", reg[rdst], pc + ((INT32)(op << 10) >> 8));
+ }
+ else
+ sprintf(buffer, "bra $%08x", pc + ((INT32)(op << 10) >> 8));
+ break;
+ case 0x03: sprintf(buffer, "lea%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x04: sprintf(buffer, "leah%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x05: sprintf(buffer, "subr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x06: sprintf(buffer, "xor%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x07: sprintf(buffer, "xorn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x08: if (!rsrc1 && !rdst && rsrc2_iszero)
+ sprintf(buffer, "nop");
+ else if (!rsrc1)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]);
+ else if (rsrc2_iszero)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]);
+ else
+ sprintf(buffer, "add%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x09: sprintf(buffer, "sub%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0a: sprintf(buffer, "addc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0b: sprintf(buffer, "subc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0c: sprintf(buffer, "and%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0d: sprintf(buffer, "andn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0e: if (!rsrc1 && !rdst && rsrc2_iszero)
+ sprintf(buffer, "nop");
+ else if (!rsrc1)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]);
+ else if (rsrc2_iszero)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]);
+ else
+ sprintf(buffer, "or%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0f: sprintf(buffer, "orn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x10: sprintf(buffer, "ld%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x11: sprintf(buffer, "ldh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x12: sprintf(buffer, "lduh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x13: sprintf(buffer, "sth%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x14: sprintf(buffer, "st%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x15: sprintf(buffer, "ldb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x16: sprintf(buffer, "ldub%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x17: sprintf(buffer, "stb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x18: sprintf(buffer, "ashr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x19: sprintf(buffer, "lshr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1a: sprintf(buffer, "ashl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1b: sprintf(buffer, "rotl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1c: sprintf(buffer, "getps %s", reg[rdst]); break;
+ case 0x1d: sprintf(buffer, "putps %s", src2(op,0)); break;
+ case 0x1e: if (rdst && rsrc2_iszero)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "jsr%s %s,%s", setcond[cond], reg[rdst], reg[rsrc1]);
+ }
+ else if (rdst)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "jsr%s %s,%s[%s]", setcond[cond], reg[rdst], reg[rsrc1], src2(op,2));
+ }
+ else if (rsrc2_iszero)
+ {
+ if (rsrc1 == 28)
+ flags = DASMFLAG_STEP_OUT;
+ sprintf(buffer, "jmp%s %s", setcond[cond], reg[rsrc1]);
+ }
+ else
+ sprintf(buffer, "jmp%s %s[%s]", setcond[cond], reg[rsrc1], src2(op,2));
+ break;
+ case 0x1f: sprintf(buffer, "trap $1f"); flags = DASMFLAG_STEP_OVER; break;
+ }
+
+ sprintf(buffer, "????");
+#endif
+ return 4 | 2 | SUPPORTED;
+}
diff --git a/src/devices/cpu/dspp/dsppdasm.h b/src/devices/cpu/dspp/dsppdasm.h
new file mode 100644
index 00000000000..7f0c526e18a
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppdasm.h
@@ -0,0 +1,22 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/*
+ DSPP disassembler shim
+*/
+
+#ifndef MAME_CPU_DSPP_DSPPDASM_H
+#define MAME_CPU_DSPP_DSPPDASM_H
+
+#pragma once
+
+class dspp_disassembler : public util::disasm_interface
+{
+public:
+ dspp_disassembler() = default;
+ virtual ~dspp_disassembler() = default;
+
+ virtual uint32_t opcode_alignment() const override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+};
+
+#endif
diff --git a/src/devices/cpu/dspp/dsppdrc.cpp b/src/devices/cpu/dspp/dsppdrc.cpp
new file mode 100644
index 00000000000..6c1e60b4874
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppdrc.cpp
@@ -0,0 +1,970 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+
+/******************************************************************************
+
+ DSPP UML recompiler core
+
+******************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "dspp.h"
+#include "dsppfe.h"
+#include "cpu/drcfe.h"
+#include "cpu/drcuml.h"
+#include "cpu/drcumlsh.h"
+
+using namespace uml;
+
+#define USE_SWAPDQ 0
+
+
+// map variables
+#define MAPVAR_PC M0
+#define MAPVAR_CYCLES M1
+#define MAPVAR_ACC M2
+
+// exit codes
+#define EXECUTE_OUT_OF_CYCLES 0
+#define EXECUTE_MISSING_CODE 1
+#define EXECUTE_UNMAPPED_CODE 2
+#define EXECUTE_RESET_CACHE 3
+
+#define FLAG_C(reg) mem(&m_core->m_flag_carry)
+#define FLAG_Z(reg) mem(&m_core->m_flag_zero)
+#define FLAG_N(reg) mem(&m_core->m_flag_neg)
+#define FLAG_V(reg) mem(&m_core->m_flag_over)
+#define FLAG_X(reg) mem(&m_core->m_flag_exact)
+
+inline void dspp_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name)
+{
+ if (*handleptr == nullptr)
+ *handleptr = drcuml->handle_alloc(name);
+}
+
+static inline uint32_t epc(const opcode_desc *desc)
+{
+ return desc->pc;
+}
+
+
+#if 0
+static void cfunc_unimplemented(void *param)
+{
+ dspp_device *dspp = (dspp_device *)param;
+ dspp->cfunc_unimplemented();
+}
+#endif
+
+void dspp_device::cfunc_unimplemented()
+{
+// uint64_t op = m_core->m_arg0;
+// fatalerror("PC=%08X: Unimplemented op %04X%08X\n", m_core->m_pc, (uint32_t)(op >> 32), (uint32_t)(op));
+}
+
+
+/*-------------------------------------------------
+load_fast_iregs - load any fast integer
+registers
+-------------------------------------------------*/
+
+inline void dspp_device::load_fast_iregs(drcuml_block &block)
+{
+#if 0 // TODO
+ for (uint32_t regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ {
+ if (m_regmap[regnum].is_int_register())
+ {
+ UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum]));
+ }
+ }
+#endif
+}
+
+
+/*-------------------------------------------------
+save_fast_iregs - save any fast integer
+registers
+-------------------------------------------------*/
+
+void dspp_device::save_fast_iregs(drcuml_block &block)
+{
+#if 0 // TODO
+ int regnum;
+
+ for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ {
+ if (m_regmap[regnum].is_int_register())
+ {
+ UML_MOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0));
+ }
+ }
+#endif
+}
+
+#if 0
+void dspp_device::static_generate_memory_accessor(MEM_ACCESSOR_TYPE type, const char *name, code_handle *&handleptr)
+{
+ // I0 = read/write data
+ // I1 = address
+
+ drcuml_block &block = m_drcuml->begin_block(1024);
+
+ // add a global entry for this
+ alloc_handle(m_drcuml.get(), &handleptr, name);
+ UML_HANDLE(block, *handleptr); // handle *handleptr
+
+ switch (type)
+ {
+ case MEM_ACCESSOR_PM_READ48:
+ UML_SHL(block, I1, I1, 3);
+ UML_DREAD(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM);
+ break;
+
+ case MEM_ACCESSOR_PM_WRITE48:
+ UML_SHL(block, I1, I1, 3);
+ UML_DWRITE(block, I1, I0, SIZE_QWORD, SPACE_PROGRAM);
+ UML_MOV(block, mem(&m_core->force_recompile), 1);
+ break;
+
+ case MEM_ACCESSOR_PM_READ32:
+ UML_SHL(block, I1, I1, 3);
+ UML_READ(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM);
+ break;
+
+ case MEM_ACCESSOR_PM_WRITE32:
+ UML_SHL(block, I1, I1, 3);
+ UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_PROGRAM);
+ UML_MOV(block, mem(&m_core->force_recompile), 1);
+ break;
+
+ case MEM_ACCESSOR_DM_READ32:
+ UML_SHL(block, I1, I1, 2);
+ UML_READ(block, I0, I1, SIZE_DWORD, SPACE_DATA);
+ break;
+
+ case MEM_ACCESSOR_DM_WRITE32:
+ UML_SHL(block, I1, I1, 2);
+ UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_DATA);
+ break;
+ }
+
+ UML_RET(block);
+
+ block.end();
+}
+#endif
+
+
+void dspp_device::execute_run_drc()
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ int execute_result;
+
+ if (m_cache_dirty)
+ flush_cache();
+
+ m_cache_dirty = false;
+
+ do
+ {
+ execute_result = drcuml->execute(*m_entry);
+
+ /* if we need to recompile, do it */
+ if (execute_result == EXECUTE_MISSING_CODE)
+ {
+ compile_block(m_core->m_pc);
+ }
+ else if (execute_result == EXECUTE_UNMAPPED_CODE)
+ {
+ fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->m_pc);
+ }
+ else if (execute_result == EXECUTE_RESET_CACHE)
+ {
+ flush_cache();
+ }
+ } while (execute_result != EXECUTE_OUT_OF_CYCLES);
+}
+
+void dspp_device::compile_block(offs_t pc)
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ compiler_state compiler = { 0 };
+ const opcode_desc *seqhead, *seqlast;
+ const opcode_desc *desclist;
+ int override = false;
+
+ g_profiler.start(PROFILER_DRC_COMPILE);
+
+ /* get a description of this sequence */
+ desclist = m_drcfe->describe_code(pc);
+
+ bool succeeded = false;
+ while (!succeeded)
+ {
+ try
+ {
+ /* start the block */
+ drcuml_block &block = drcuml->begin_block(4096);
+
+ /* loop until we get through all instruction sequences */
+ for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next())
+ {
+ const opcode_desc *curdesc;
+ uint32_t nextpc;
+
+ /* add a code log entry */
+ if (drcuml->logging())
+ block.append_comment("-------------------------"); // comment
+
+ /* determine the last instruction in this sequence */
+ for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next())
+ if (seqlast->flags & OPFLAG_END_SEQUENCE)
+ break;
+ assert(seqlast != nullptr);
+
+ /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */
+ if (override || !drcuml->hash_exists(0, seqhead->pc))
+ UML_HASH(block, 0, seqhead->pc); // hash mode,pc
+
+ /* if we already have a hash, and this is the first sequence, assume that we */
+ /* are recompiling due to being out of sync and allow future overrides */
+ else if (seqhead == desclist)
+ {
+ override = true;
+ UML_HASH(block, 0, seqhead->pc); // hash mode,pc
+ }
+
+ /* otherwise, redispatch to that fixed PC and skip the rest of the processing */
+ else
+ {
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc
+ UML_HASHJMP(block, 0, seqhead->pc, *m_nocode);
+ // hashjmp <0>,seqhead->pc,nocode
+ continue;
+ }
+
+ generate_checksum_block(block, &compiler, seqhead, seqlast);
+
+ /* label this instruction, if it may be jumped to locally */
+ if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc
+
+ /* iterate over instructions in the sequence and compile them */
+ for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
+ generate_sequence_instruction(block, &compiler, curdesc);
+
+ /* if we need to return to the start, do it */
+ if (seqlast->flags & OPFLAG_RETURN_TO_START)
+ nextpc = pc;
+
+ /* otherwise we just go to the next instruction */
+ else
+ nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
+
+ /* count off cycles and go there */
+ generate_update_cycles(block, &compiler, nextpc); // <subtract cycles>
+
+ /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
+ if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc)
+ UML_HASHJMP(block, 0, nextpc, *m_nocode); // hashjmp <mode>,nextpc,nocode
+ }
+
+ /* end the sequence */
+ block.end();
+ g_profiler.stop();
+ succeeded = true;
+ }
+ catch (drcuml_block::abort_compilation &)
+ {
+ flush_cache();
+ }
+ }
+}
+
+void dspp_device::generate_checksum_block(drcuml_block &block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast)
+{
+ const opcode_desc *curdesc;
+ if (m_drcuml->logging())
+ block.append_comment("[Validation for %08X]", seqhead->pc); // comment
+
+ /* loose verify or single instruction: just compare and fail */
+ if (!(m_drcoptions & DSPPDRC_STRICT_VERIFY) || seqhead->next() == nullptr)
+ {
+ if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ uint32_t sum = seqhead->opptr.l[0];
+ uint32_t addr = seqhead->physpc;
+ const void *base = m_codeptr(addr);
+ UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
+
+ if (seqhead->delay.first() != nullptr && seqhead->physpc != seqhead->delay.first()->physpc)
+ {
+ addr = seqhead->delay.first()->physpc;
+ base = m_codeptr(addr);
+ assert(base != nullptr);
+ UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+
+ sum += seqhead->delay.first()->opptr.l[0];
+ }
+
+ UML_CMP(block, I0, sum); // cmp i0,opptr[0]
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ }
+ }
+
+ /* full verification; sum up everything */
+ else
+ {
+#if 0
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ void *base = m_code_direct->read_ptr(seqhead->physpc);
+ UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
+ UML_CMP(block, I0, curdesc->opptr.l[0]); // cmp i0,opptr[0]
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ }
+#else
+ uint32_t sum = 0;
+ uint32_t addr = seqhead->physpc;
+ const void *base = m_codeptr(addr);
+ UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
+ sum += seqhead->opptr.l[0];
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ addr = curdesc->physpc;
+ base = m_codeptr(addr);
+ assert(base != nullptr);
+ UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->opptr.l[0];
+
+ if (curdesc->delay.first() != nullptr && (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
+ {
+ addr = curdesc->delay.first()->physpc;
+ base = m_codeptr(addr);
+ assert(base != nullptr);
+ UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->delay.first()->opptr.l[0];
+ }
+ }
+ UML_CMP(block, I0, sum); // cmp i0,sum
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+#endif
+ }
+}
+
+
+void dspp_device::flush_cache()
+{
+ /* empty the transient cache contents */
+ m_drcuml->reset();
+
+ try
+ {
+ // generate the entry point and out-of-cycles handlers
+ static_generate_entry_point();
+ static_generate_nocode_handler();
+ static_generate_out_of_cycles();
+
+#if 0
+ // generate utility functions
+ static_generate_push_pc();
+ static_generate_pop_pc();
+ static_generate_push_loop();
+ static_generate_pop_loop();
+ static_generate_push_status();
+ static_generate_pop_status();
+ static_generate_mode1_ops();
+
+ // generate exception handlers
+ static_generate_exception(EXCEPTION_INTERRUPT, "exception_interrupt");
+
+ // generate memory accessors
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_READ48, "pm_read48", m_pm_read48);
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE48, "pm_write48", m_pm_write48);
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_READ32, "pm_read32", m_pm_read32);
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE32, "pm_write32", m_pm_write32);
+ static_generate_memory_accessor(MEM_ACCESSOR_DM_READ32, "dm_read32", m_dm_read32);
+ static_generate_memory_accessor(MEM_ACCESSOR_DM_WRITE32, "dm_write32", m_dm_write32);
+#endif
+ }
+ catch (drcuml_block::abort_compilation &)
+ {
+ fatalerror("Error generating dspp static handlers\n");
+ }
+}
+
+
+void dspp_device::static_generate_entry_point()
+{
+ /* begin generating */
+ drcuml_block &block = m_drcuml->begin_block(20);
+
+ /* forward references */
+ alloc_handle(m_drcuml.get(), &m_nocode, "nocode");
+// alloc_handle(m_drcuml.get(), &m_exception[EXCEPTION_INTERRUPT], "exception_interrupt");
+
+ alloc_handle(m_drcuml.get(), &m_entry, "entry");
+ UML_HANDLE(block, *m_entry); // handle entry
+
+ load_fast_iregs(block); // <load fastregs>
+
+#if 0 // TODO: No interrupts?
+ /* check for interrupts */
+ UML_CMP(block, mem(&m_core->irq_pending), 0); // cmp [irq_pending],0
+ UML_JMPc(block, COND_E, skip); // je skip
+ UML_CMP(block, mem(&m_core->interrupt_active), 0); // cmp [interrupt_active],0
+ UML_JMPc(block, COND_NE, skip); // jne skip
+ UML_TEST(block, mem(&m_core->irq_pending), IMASK); // test [irq_pending],IMASK
+ UML_JMPc(block, COND_Z, skip); // jz skip
+ UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN); // test MODE1,MODE1_IRPTEN
+ UML_JMPc(block, COND_Z, skip); // jz skip
+#endif
+
+// UML_MOV(block, I0, mem(&m_core->m_pc)); // mov i0,nextpc
+// UML_MOV(block, I1, 0); // mov i1,0
+// UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]); // callh m_exception[EXCEPTION_INTERRUPT]
+
+// UML_LABEL(block, skip);
+
+ /* generate a hash jump via the current mode and PC */
+ UML_HASHJMP(block, 0, mem(&m_core->m_pc), *m_nocode); // hashjmp <mode>,<pc>,nocode
+
+ block.end();
+}
+
+
+void dspp_device::static_generate_nocode_handler()
+{
+ /* begin generating */
+ drcuml_block &block = m_drcuml->begin_block(10);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(m_drcuml.get(), &m_nocode, "nocode");
+ UML_HANDLE(block, *m_nocode); // handle nocode
+ UML_GETEXP(block, I0); // getexp i0
+ UML_MOV(block, mem(&m_core->m_pc), I0); // mov [pc],i0
+ save_fast_iregs(block); // <save fastregs>
+ UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
+
+ block.end();
+}
+
+void dspp_device::static_generate_out_of_cycles()
+{
+ /* begin generating */
+ drcuml_block &block = m_drcuml->begin_block(10);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(m_drcuml.get(), &m_out_of_cycles, "out_of_cycles");
+ UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles
+ UML_GETEXP(block, I0); // getexp i0
+ UML_MOV(block, mem(&m_core->m_pc), I0); // mov <pc>,i0
+ save_fast_iregs(block); // <save fastregs>
+ UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES
+
+ block.end();
+}
+
+
+void dspp_device::generate_sequence_instruction(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ /* add an entry for the log */
+// if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
+// log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]);
+
+ /* set the PC map variable */
+ UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,desc->pc
+
+ /* accumulate total cycles */
+ compiler->cycles += desc->cycles;
+
+ /* update the icount map variable */
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+
+ /* if we are debugging, call the debugger */
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ {
+ UML_MOV(block, mem(&m_core->m_pc), desc->pc); // mov [pc],desc->pc
+ save_fast_iregs(block); // <save fastregs>
+ UML_DEBUG(block, desc->pc); // debug desc->pc
+ }
+
+ /* if we hit an unmapped address, fatal error */
+ if (desc->flags & OPFLAG_COMPILER_UNMAPPED)
+ {
+ UML_MOV(block, mem(&m_core->m_pc), desc->pc); // mov [pc],desc->pc
+ save_fast_iregs(block); // <save fastregs>
+ UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE
+ }
+
+ /* if this is an invalid opcode, generate the exception now */
+// if (desc->flags & OPFLAG_INVALID_OPCODE)
+// UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000
+
+ /* unless this is a virtual no-op, it's a regular instruction */
+ if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ /* compile the instruction */
+ //if (!generate_opcode(block, compiler, desc))
+ {
+ UML_MOV(block, mem(&m_core->m_pc), desc->pc); // mov [pc],desc->pc
+ UML_DMOV(block, mem(&m_core->m_arg0), desc->opptr.q[0]); // dmov [m_arg0],*desc->opptr.q // FIXME
+// UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented,ppc
+ }
+ }
+}
+
+void dspp_device::generate_update_cycles(drcuml_block &block, compiler_state *compiler, uml::parameter param)
+{
+#if 0 // No interrupts
+ if (compiler->checkints)
+ {
+ code_label skip = compiler->labelnum++;
+ compiler->checkints = false;
+
+ UML_CMP(block, mem(&m_core->irq_pending), 0); // cmp [irq_pending],0
+ UML_JMPc(block, COND_E, skip); // je skip
+ UML_CMP(block, mem(&m_core->interrupt_active), 0); // cmp [interrupt_active],0
+ UML_JMPc(block, COND_NE, skip); // jne skip
+ UML_TEST(block, mem(&m_core->irq_pending), IMASK); // test [irq_pending],IMASK
+ UML_JMPc(block, COND_Z, skip); // jz skip
+ UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN); // test MODE1,MODE1_IRPTEN
+ UML_JMPc(block, COND_Z, skip); // jz skip
+
+ UML_MOV(block, I0, param); // mov i0,nextpc
+ UML_MOV(block, I1, compiler->cycles); // mov i1,cycles
+ UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]); // callh m_exception[EXCEPTION_INTERRUPT]
+
+ UML_LABEL(block, skip);
+ }
+#endif
+
+ /* account for cycles */
+ if (compiler->cycles > 0)
+ {
+ UML_SUB(block, mem(&m_core->m_icount), mem(&m_core->m_icount), MAPVAR_CYCLES); // sub icount,icount,cycles
+ UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0
+#if 0 // FIXME
+ if (allow_exception)
+ UML_EXHc(block, COND_S, *m_out_of_cycles, param); // exh out_of_cycles,nextpc
+#endif
+ }
+ compiler->cycles = 0;
+}
+
+#if 0
+bool dspp_device::generate_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t op = desc->opptr.l[0];
+
+ if (op & 0x8000)
+ {
+ switch ((op >> 13) & 3)
+ {
+ case 0:
+ return generate_special_opcode(op, desc);
+
+ case 1:
+ case 2:
+ return generate_branch_opcode(op, desc);
+
+ case 3:
+ return generate_complex_branch_opcode(op, desc);
+ }
+
+ return false;
+ }
+ else
+ {
+ return generate_arithmetic_opcode(op, desc);
+ }
+
+ return false;
+}
+
+bool dspp_device::generate_special_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ return true;
+}
+
+bool dspp_device::generate_branch_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t mode = (m_core->m_op >> 13) & 3;
+ uint32_t select = (m_core->m_op >> 12) & 1;
+ uint32_t mask = (m_core->m_op >> 10) & 3;
+
+ bool flag0, flag1;
+
+ if (select == 0)
+ {
+ flag0 = (m_core->m_flags & DSPI_FLAG_CC_NEG) != 0;
+ flag1 = (m_core->m_flags & DSPI_FLAG_CC_OVER) != 0;
+ }
+ else
+ {
+ flag0 = (m_core->m_flags & DSPI_FLAG_CC_CARRY) != 0;
+ flag1 = (m_core->m_flags & DSPI_FLAG_CC_ZERO) != 0;
+ }
+
+ bool mask0 = (mask & 2) != 0;
+ bool mask1 = (mask & 1) != 0;
+
+ bool branch = (flag0 || !mask0) && (flag1 || !mask1);
+
+ if (mode == 2)
+ branch = !branch;
+
+ if (branch)
+ m_core->m_pc = m_core->m_op & 0x3ff;
+
+ return true;
+}
+
+
+void adsp21062_device::generate_jump(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc, bool delayslot, bool loopabort, bool clearint)
+{
+ compiler_state compiler_temp = *compiler;
+
+ // save branch target
+ if (desc->targetpc == BRANCH_TARGET_DYNAMIC)
+ {
+ UML_MOV(block, mem(&m_core->jmpdest), I0); // mov [jmpdest],i0
+ }
+
+ // update cycles and hash jump
+ if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
+ {
+ generate_update_cycles(block, &compiler_temp, desc->targetpc, true);
+ if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
+ UML_JMP(block, desc->targetpc | 0x80000000); // jmp targetpc | 0x80000000
+ else
+ UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp 0,targetpc,nocode
+ }
+ else
+ {
+ generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), true);
+ UML_HASHJMP(block, 0, mem(&m_core->jmpdest), *m_nocode); // hashjmp 0,jmpdest,nocode
+ }
+
+ // update compiler label
+ compiler->labelnum = compiler_temp.labelnum;
+
+ /* reset the mapvar to the current cycles and account for skipped slots */
+// compiler->cycles += desc->skipslots;
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+}
+
+bool dspp_device::generate_complex_branch_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t op = desc->opptr.l[0];
+
+ code_label skip_label = compiler->labelnum++;
+
+// generate_branch_target(block, compiler, desc, op & 0x3ff, ef2);
+// generate_condition(block, compiler, desc, ef1, true, skip_label, true);
+ generate_branch(block, compiler, desc);
+ UML_LABEL(block, skip_label);
+
+ switch ((op >> 10) & 7)
+ {
+ case 0: // BLT
+ // branch = (n && !v) || (!n && v);
+ UML_XOR(I0, FLAG_N, 1);
+ UML_XOR(I1, FLAG_V, 1);
+ UML_AND(I0, I0, FLAG_V);
+ UML_AND(I1, FLAG_N, I1);
+ UML_OR(I0, I1, I2);
+ UML_CMP(block, I0, 1);
+ break;
+ case 1: // BLE
+ //branch = ((n && !v) || (!n && v)) || z;
+ break;
+ case 2: // BGE
+ //branch = ((n && v) || (!n && !v));
+ break;
+ case 3: // BGT
+ //branch = ((n && v) || (!n && !v)) && !z;
+ UML_AND(I2, FLAG_N, FLAG_V);
+ UML_XOR(I0, FLAG_N, 1);
+ UML_XOR(I1, FLAG_V, 1);
+ UML_AND(I0, I0, I1);
+ UML_OR(I0, I2, I0);
+ UML_XOR(I1, FLAG_Z, 1);
+ UML_AND(I0, I0, I1);
+ UML_CMP(I0, 1);
+ break;
+ case 4: // BHI
+ //branch = c && !z;
+ UML_XOR(I0, FLAG_Z, 1)
+ UML_AND(I0, FLAG_C, I0);
+ UML_CMP(I0, 1);
+ break;
+ case 5: // BLS
+ //branch = !c || z;
+ UML_XOR(I0, FLAG_C, 1);
+ UML_OR(I0, I0, FLAG_Z);
+ UML_CMP(block, I0, 1);
+ break;
+ case 6: // BXS
+ //branch = x;
+ UML_CMP(block, FLAG_X, 1);
+ break;
+ case 7: // BXC
+ //branch = !x;
+ UML_CMP(block, FLAG_X, 0);
+ break;
+ }
+
+ UML_JMPc(block, COND_E, skip_label);
+
+ return true;
+}
+
+bool dspp_device::generate_arithmetic_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t numops = (m_core->m_op >> 13) & 3;
+ uint32_t muxa = (m_core->m_op >> 10) & 3;
+ uint32_t muxb = (m_core->m_op >> 8) & 3;
+ uint32_t alu_op = (m_core->m_op >> 4) & 0xf;
+ uint32_t barrel_code = m_core->m_op & 0xf;
+
+ int32_t mul_res = 0;
+ uint32_t alu_res = 0;
+
+ // Check for operand overflow
+ if (numops == 0 && ((muxa == 1) || (muxa == 2) || (muxb == 1) || (muxb == 2)))
+ numops = 4;
+
+ // Implicit barrel shift
+ if (barrel_code == 8)
+ ++numops;
+
+ // Parse ops...
+ parse_operands(numops);
+
+ if (muxa == 3 || muxb == 3)
+ {
+ uint32_t mul_sel = (m_core->m_op >> 12) & 1;
+
+ int32_t op1 = sign_extend16(read_next_operand());
+ int32_t op2 = sign_extend16(mul_sel ? read_next_operand() : m_core->m_acc >> 4);
+
+ mul_res = (op1 * op2) >> 11;
+
+#if 0
+ // SELECT
+ UML_DSEXT(block, I0, OP1, SIZE_WORD);
+ UML_DSEXT(block, I1, OP1, SIZE_WORD);
+ UML_MULS(block, I0, I1, I0, I1);
+ UML_SHR(block, I2, I0, 11);
+#endif
+ }
+
+ // MULRES = I2
+ // MUXA = I0
+ // MUXB = I1
+
+ // ALURES = I2
+ // ACC_RESULT = I1?
+ switch (alu_op)
+ {
+ case 0: // _TRA
+ // alu_res = alu_a;
+ UML_MOV(block, I2, I0);
+ break;
+
+ case 1: // _NEG
+ // alu_res = -alu_b;
+ UML_SUB(block, I2, 0, I1);
+ break;
+
+ case 2: // _+
+ // alu_res = alu_a + alu_b;
+ UML_ADD(block, I2, I0, I1);
+
+ // if ((alu_a & 0x80000) == (alu_b & 0x80000) &&
+ // (alu_a & 0x80000) != (alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ // CC_V_MODIFIED(desc);
+ // CC_C_MODIFIED(desc);
+ break;
+
+ case 3: // _+C
+ UML_ADD(block, I2, I0, mew);
+ // alu_res = alu_a + (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+
+ case 4: // _-
+ // alu_res = alu_a - alu_b;
+ UML_SUB(block, I2, I0, I1);
+
+ // if ((alu_a & 0x80000) == (~alu_b & 0x80000) &&
+ // (alu_a & 0x80000) != (alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_MODIFIED(desc);
+ CC_V_MODIFIED(desc);
+ break;
+
+ case 5: // _-B
+ // alu_res = alu_a - (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+
+ case 6: // _++
+ UML_ADD(block, I2, I0, 1);
+ // alu_res = alu_a + 1;
+
+ // if (!(alu_a & 0x80000) && (alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+
+ case 7: // _--
+ // alu_res = alu_a - 1;
+ UML_SUB(block, I2, I0, 1);
+
+ // if ((alu_a & 0x80000) && !(alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+
+ case 8: // _TRL
+ //alu_res = alu_a;
+ UML_MOV(block, I2, I0);
+ break;
+
+ case 9: // _NOT
+ //alu_res = ~alu_a;
+ UML_XOR(block, I2, I0, 0xffff);
+ break;
+
+ case 10: // _AND
+ //alu_res = alu_a & alu_b;
+ UML_AND(block, I2, I0, I1);
+ break;
+
+ case 11: // _NAND
+ //alu_res = ~(alu_a & alu_b);
+ UML_AND(block, I2, I0, I1);
+ UML_XOR(block, I2, 0xffff);
+ break;
+
+ case 12: // _OR
+ //alu_res = alu_a | alu_b;
+ UML_OR(block, I2, I0, I1);
+ break;
+
+ case 13: // _NOR
+ //alu_res = ~(alu_a | alu_b);
+ UML_OR(block, I2, I0, I1);
+ UML_XOR(block, I2, I2, 0xffff);
+ break;
+
+ case 14: // _XOR
+ //alu_res = alu_a ^ alu_b;
+ UML_XOR(block, I2, I0, I1);
+ break;
+
+ case 15: // _XNOR
+ //alu_res = ~(alu_a ^ alu_b);
+ UML_XOR(block, I2, I0, I1);
+ UML_XOR(block, I2, I0, 0xffff);
+ break;
+ }
+
+ // SET FLAGS
+ CC_SET_NEG(alu_res & 0x00080000);
+ CC_SET_ZERO((alu_res & 0x000ffff0) == 0);
+ CC_SET_EXACT((alu_res & 0x0000000f) == 0);
+
+ // Barrel shift
+ static const int32_t shifts[8] = { 0, 1, 2, 3, 4, 5, 8, 16 };
+
+ if (barrel_code == 8)
+ barrel_code = read_next_operand();
+
+ if (barrel_code & 8)
+ {
+ // Right shift
+ uint32_t shift = shifts[(~barrel_code + 1) & 7];
+
+ if (alu_op < 8)
+ {
+ // Arithmetic
+// m_core->m_acc = sign_extend20(alu_res) >> shift;
+
+ // TODO: Sign Extend to 20-bits
+ UML_SHR(block, I2, I2, shift);
+ UML_MAPVAR(block, MAPVAR_ACC, I2);
+ }
+ else
+ {
+ // Logical
+// m_core->m_acc = (alu_res & 0xfffff) >> shift;
+ UML_AND(block, I2, 0xfffff);
+ UML_SHR(block, I2, I2, shift);
+ UML_MAPVAR(block, MAPVAR_ACC, I2);
+ }
+
+ }
+ else
+ {
+ // Left shift
+ uint32_t shift = shifts[barrel_code];
+
+ if (shift == 16)
+ {
+ // Clip and saturate
+ if (m_core->m_flags & DSPI_FLAG_CC_OVER)
+ m_core->m_acc = (m_core->m_flags & DSPI_FLAG_CC_NEG) ? 0x7ffff : 0xfff80000;
+ else
+ m_core->m_acc = sign_extend20(alu_res);
+ }
+ else
+ {
+ m_core->m_acc = sign_extend20(alu_res) << shift;
+ }
+ }
+
+ if (m_core->m_writeback >= 0)
+ {
+ write_data(m_core->m_writeback, m_core->m_acc >> 4);
+ m_core->m_writeback = -1;
+ }
+ else if (m_core->m_opidx < numops)
+ {
+ write_next_operand(m_core->m_acc >> 4);
+ }
+
+ return true;
+}
+
+#endif
diff --git a/src/devices/cpu/dspp/dsppfe.cpp b/src/devices/cpu/dspp/dsppfe.cpp
new file mode 100644
index 00000000000..533a020ab89
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppfe.cpp
@@ -0,0 +1,625 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+
+/******************************************************************************
+
+ Front-end for DSPP recompiler
+
+******************************************************************************/
+
+#include "emu.h"
+#include "dsppfe.h"
+
+
+//#define REG_USED(desc,x) do { (desc).regin[0] |= 1 << (x); } while(0)
+//#define REG_MODIFIED(desc,x) do { (desc).regout[0] |= 1 << (x); } while(0)
+
+#define CC_C_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_C_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_Z_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_Z_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_N_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_N_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_V_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_V_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_X_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_X_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+
+#define CC_FLAGS_MODIFIED(desc) do { } while(0)
+//#define MULT_FLAGS_MODIFIED(desc) do { MN_MODIFIED(desc);MV_MODIFIED(desc);MU_MODIFIED(desc);MI_MODIFIED(desc); } while(0)
+//#define SHIFT_FLAGS_MODIFIED(desc) do { SZ_MODIFIED(desc);SV_MODIFIED(desc);SS_MODIFIED(desc); } while(0)
+
+dspp_frontend::dspp_frontend(dspp_device *dspp, uint32_t window_start, uint32_t window_end, uint32_t max_sequence)
+ : drc_frontend(*dspp, window_start, window_end, max_sequence),
+ m_dspp(dspp)
+{
+
+}
+
+
+#if 0
+// opcode branch flags
+const uint32_t OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch
+const uint32_t OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch
+const uint32_t OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH);
+const uint32_t OPFLAG_IS_BRANCH_TARGET = 0x00000004; // instruction is the target of a branch
+const uint32_t OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch
+const uint32_t OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block
+
+// opcode exception flags
+const uint32_t OPFLAG_CAN_TRIGGER_SW_INT = 0x00000020; // instruction can trigger a software interrupt
+const uint32_t OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt
+const uint32_t OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception
+const uint32_t OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception
+const uint32_t OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged
+
+// opcode virtual->physical translation flags
+const uint32_t OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution
+const uint32_t OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB
+const uint32_t OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing
+const uint32_t OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing
+
+// opcode flags
+const uint32_t OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid
+const uint32_t OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op
+
+// opcode sequence flow flags
+const uint32_t OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion
+const uint32_t OPFLAG_RETURN_TO_START = 0x00020000; // instruction must jump back to the beginning after completion
+const uint32_t OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence
+const uint32_t OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes
+
+// execution semantics
+const uint32_t OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory
+const uint32_t OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory
+#endif
+
+bool dspp_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
+{
+ uint16_t op = desc.opptr.w[0] = m_dspp->read_op(desc.physpc);
+
+ // TODO: NOOOOPE
+ desc.cycles = 1; // TODO: Extra cycles for extra operands
+ desc.length = 2;
+
+ // Decode and execute
+ if (op & 0x8000)
+ {
+ switch ((op >> 13) & 3)
+ {
+ case 0:
+ return describe_special(op, desc);
+
+ case 1:
+ case 2:
+ return describe_branch(op, desc);
+
+ case 3:
+ return describe_complex_branch(op, desc);
+ }
+
+ return false;
+ }
+ else
+ {
+ return describe_arithmetic(op, desc);
+ }
+
+ return false;
+}
+
+
+bool dspp_frontend::describe_special(uint16_t op, opcode_desc &desc)
+{
+ switch ((op >> 10) & 7)
+ {
+ case 0:
+ {
+ // Super-special
+ switch ((op >> 7) & 7)
+ {
+ case 1: // BAC - TODO: MERGE?
+ {
+ //desc.regin[0] = m_acc;
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ return true;
+ }
+ case 4: // RTS
+ {
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ return true;
+ }
+ case 5: // OP_MASK
+ {
+ // TODO
+ return true;
+ }
+
+ case 7: // SLEEP
+ {
+ // TODO
+ return true;
+ }
+
+ case 0: // NOP
+ case 2: // Unused
+ case 3:
+ case 6:
+ return true;
+ }
+
+ break;
+ }
+ case 1: // JUMP - TODO: MERGE?
+ {
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = op & 0x3ff;
+ return true;
+ }
+ case 2: // JSR
+ {
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = op & 0x3ff;
+ return true;
+ }
+ case 3: // BFM
+ {
+ // TODO: What sort of branch is this?
+// desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+// desc.targetpc = 0; // FIXME
+ return false;
+ }
+ case 4: // MOVEREG
+ {
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+
+ // Indirect
+ if (op & 0x0010)
+ desc.flags |= OPFLAG_READS_MEMORY;
+
+ return true;
+ }
+ case 5: // RBASE
+ {
+ return true;
+ }
+ case 6: // MOVED
+ {
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+ }
+ case 7: // MOVEI
+ {
+ desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool dspp_frontend::describe_branch(uint16_t op, opcode_desc &desc)
+{
+ const uint32_t select = (op >> 12) & 1;
+
+ if (select == 0)
+ {
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ }
+ else
+ {
+ CC_C_USED(desc);
+ CC_Z_USED(desc);
+ }
+
+ // TODO: Can these be unconditional?
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.targetpc = op & 0x3ff;
+
+ return true;
+}
+
+bool dspp_frontend::describe_complex_branch(uint16_t op, opcode_desc &desc)
+{
+ switch ((op >> 10) & 7)
+ {
+ case 0: // BLT
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ break;
+ case 1: // BLE
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ CC_Z_USED(desc);
+ break;
+ case 2: // BGE
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ break;
+ case 3: // BGT
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ CC_Z_USED(desc);
+ break;
+ case 4: // BHI
+ case 5: // BLS
+ CC_C_USED(desc);
+ CC_Z_USED(desc);
+ break;
+ case 6: // BXS
+ case 7: // BXC
+ CC_X_USED(desc);
+ break;
+ }
+
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.targetpc = op & 0x3ff;
+
+ return true;
+}
+
+bool dspp_frontend::describe_arithmetic(uint16_t op, opcode_desc &desc)
+{
+ #if 0
+ // Decode the various fields
+ uint32_t numops = (op >> 13) & 3;
+ uint32_t muxa = (op >> 10) & 3;
+ uint32_t muxb = (op >> 8) & 3;
+ uint32_t alu_op = (op >> 4) & 0xf;
+ uint32_t barrel_code = op & 0xf;
+
+ int32_t mul_res = 0;
+ uint32_t alu_res = 0;
+
+ // Check for operand overflow
+ if (numops == 0 && ((muxa == 1) || (muxa == 2) || (muxb == 1) || (muxb == 2)))
+ numops = 4;
+
+ // Implicit barrel shift
+ if (barrel_code == 8)
+ ++numops;
+
+ // TODO: We need to know:
+ // Number of cycles
+ // Number of bytes
+ // Registers read
+ // Registers written
+ // Does it read memory?
+ // Does it write memory?
+
+// parse_operands(numops);
+
+ if (muxa == 3 || muxb == 3)
+ {
+ uint32_t mul_sel = (op >> 12) & 1;
+
+ int32_t op1 = sign_extend16(read_next_operand());
+ int32_t op2 = sign_extend16(mul_sel ? read_next_operand() : m_core->m_acc >> 4);
+
+ mul_res = (op1 * op2) >> 11;
+ }
+
+ int32_t alu_a, alu_b;
+
+ switch (muxa)
+ {
+ case 0:
+ {
+ ACCUMULATOR_USED
+ alu_a = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_a = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_a = mul_res;
+ break;
+ }
+ }
+
+ switch (muxb)
+ {
+ case 0:
+ {
+ ACCUMULATOR_USED
+ alu_b = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_b = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_b = mul_res;
+ break;
+ }
+ }
+
+ // All flags ar emodifed
+ CC_FLAGS_MODIFIED(desc);
+
+ switch (alu_op)
+ {
+ case 0: // _TRA
+ {
+// alu_res = alu_a;
+ break;
+ }
+ case 1: // _NEG
+ {
+// alu_res = -alu_b;
+ break;
+ }
+ case 2: // _+
+ {
+// alu_res = alu_a + alu_b;
+
+// if ((alu_a & 0x80000) == (alu_b & 0x80000) &&
+// (alu_a & 0x80000) != (alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+// CC_V_MODIFIED(desc);
+// CC_C_MODIFIED(desc);
+ break;
+ }
+ case 3: // _+C
+ {
+// alu_res = alu_a + (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+ }
+ case 4: // _-
+ {
+// alu_res = alu_a - alu_b;
+
+// if ((alu_a & 0x80000) == (~alu_b & 0x80000) &&
+// (alu_a & 0x80000) != (alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_MODIFIED(desc);
+ CC_V_MODIFIED(desc);
+ break;
+ }
+ case 5: // _-B
+ {
+// alu_res = alu_a - (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+ }
+ case 6: // _++
+ {
+// alu_res = alu_a + 1;
+
+// if (!(alu_a & 0x80000) && (alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+ }
+ case 7: // _--
+ {
+// alu_res = alu_a - 1;
+
+// if ((alu_a & 0x80000) && !(alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+ }
+ case 8: // _TRL
+ {
+ //alu_res = alu_a;
+ break;
+ }
+ case 9: // _NOT
+ {
+ //alu_res = ~alu_a;
+ break;
+ }
+ case 10: // _AND
+ {
+ //alu_res = alu_a & alu_b;
+ break;
+ }
+ case 11: // _NAND
+ {
+ //alu_res = ~(alu_a & alu_b);
+ break;
+ }
+ case 12: // _OR
+ {
+ //alu_res = alu_a | alu_b;
+ break;
+ }
+ case 13: // _NOR
+ {
+ //alu_res = ~(alu_a | alu_b);
+ break;
+ }
+ case 14: // _XOR
+ {
+ //alu_res = alu_a ^ alu_b;
+ break;
+ }
+ case 15: // _XNOR
+ {
+ //alu_res = ~(alu_a ^ alu_b);
+ break;
+ }
+ }
+
+
+ if (alu_res & 0x00080000)
+ m_core->m_flags |= DSPI_FLAG_CC_NEG;
+
+ if ((alu_res & 0x000ffff0) == 0)
+ m_core->m_flags |= DSPI_FLAG_CC_ZERO;
+
+ if ((alu_res & 0x0000000f) == 0)
+ m_core->m_flags |= DSPI_FLAG_CC_EXACT;
+
+ CC_N_MODIFIED(desc);
+ CC_Z_MODIFIED(desc);
+ CC_X_MODIFIED(desc);
+
+ ACCUMULATOR_MODIFIED_ALWAYS;
+
+ // Barrel shift
+ static const int32_t shifts[8] = { 0, 1, 2, 3, 4, 5, 8, 16 };
+
+ if (barrel_code == 8)
+ barrel_code = read_next_operand();
+
+ if (barrel_code & 8)
+ {
+ // Right shift
+ uint32_t shift = shifts[(~barrel_code + 1) & 7];
+
+ if (alu_op < 8)
+ {
+ // Arithmetic
+ m_core->m_acc = sign_extend20(alu_res) >> shift;
+ }
+ else
+ {
+ // Logical
+ m_core->m_acc = (alu_res & 0xfffff) >> shift;
+ }
+ }
+ else
+ {
+ // Left shift
+ uint32_t shift = shifts[barrel_code];
+
+ if (shift == 16)
+ {
+ // Clip and saturate
+ if (m_core->m_flags & DSPI_FLAG_CC_OVER)
+ m_core->m_acc = (m_core->m_flags & DSPI_FLAG_CC_NEG) ? 0x7ffff : 0xfff80000;
+ else
+ m_core->m_acc = sign_extend20(alu_res);
+ }
+ else
+ {
+ m_core->m_acc = sign_extend20(alu_res) << shift;
+ }
+ }
+
+ if (m_core->m_writeback >= 0)
+ {
+ write_data(m_core->m_writeback, m_core->m_acc >> 4);
+ m_core->m_writeback = -1;
+ }
+ else if (opidx < numops)
+ {
+ write_next_operand(m_core->m_acc >> 4);
+ }
+#endif
+ return true;
+}
+
+
+#if 0
+void dspp_device::parse_operands(uint32_t numops)
+{
+ uint32_t addr, val = 0xBAD;
+ uint32_t opidx = 0;
+ uint32_t operand = 0;
+ uint32_t numregs = 0;
+
+ uint32_t opidx = 0;
+
+ while (opidx < numops)
+ {
+ uint16_t op = desc.opptr.w[opidx + 1] = m_dspp->read_op(desc.physpc + opidx * 2);
+
+ desc.length += 2;
+ ++desc.cycles;
+
+ if (op & 0x8000)
+ {
+ // Immediate value
+ if ((op & 0xc000) == 0xc000)
+ {
+ // Nothing?-
+ }
+ else if((op & 0xe000) == 0x8000)
+ {
+ if (op & 0x0400) // Indirect
+ desc.flags |= OPFLAG_READS_MEMORY;
+
+ if (op & 0x0800 )// Write Back
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+
+ ++opidx;
+ }
+ else if ((op & 0xe000) == 0xa000)
+ {
+ // 1 or 2 register operand
+ numregs = (op & 0x0400) ? 2 : 1;
+ }
+ }
+ else
+ {
+ numregs = 3;
+ }
+
+ if (numregs > 0)
+ {
+ // Shift successive register operands from a single operand word
+ for (uint32_t i = 0; i < numregs; ++i)
+ {
+ uint32_t shift = ((numregs - i) - 1) * 5;
+ uint32_t regdi = (operand >> shift) & 0x1f;
+ // OP USES REGBASE?
+
+ if (regdi & 0x0010)
+ {
+ // Indirect
+ desc.flags |= OPFLAG_READS_MEMORY;
+ }
+
+ if (numregs == 2)
+ {
+ // Write back
+ if ((i == 0) && (operand & 0x1000))
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ else if ((i == 1) && (operand & 0x0800))
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ }
+ else if (numregs == 1)
+ {
+ if (operand & 0x800)
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ }
+ }
+ numregs = 0;
+ }
+ }
+}
+#endif
diff --git a/src/devices/cpu/dspp/dsppfe.h b/src/devices/cpu/dspp/dsppfe.h
new file mode 100644
index 00000000000..a90dc5d0225
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppfe.h
@@ -0,0 +1,72 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dsppfe.h
+
+ Front-end for DSPP recompiler
+
+***************************************************************************/
+
+#ifndef DEVICES_CPU_DSPP_DSPPFE_H
+#define DEVICES_CPU_DSPP_DSPPFE_H
+
+#include "dspp.h"
+#include "cpu/drcfe.h"
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+// register flags 0
+#define REGFLAG_R(n) (1 << (n))
+#define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n))
+
+// register flags 1
+#define REGFLAG_FR(n) (1 << (n))
+
+// register flags 2
+#define REGFLAG_CR(n) (0xf0000000 >> (4 * (n)))
+#define REGFLAG_CR_BIT(n) (0x80000000 >> (n))
+
+// register flags 3
+#define REGFLAG_XER_CA (1 << 0)
+#define REGFLAG_XER_OV (1 << 1)
+#define REGFLAG_XER_SO (1 << 2)
+#define REGFLAG_XER_COUNT (1 << 3)
+#define REGFLAG_CTR (1 << 4)
+#define REGFLAG_LR (1 << 5)
+#define REGFLAG_FPSCR(n) (1 << (6 + (n)))
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class dspp_frontend : public drc_frontend
+{
+public:
+ // construction/destruction
+ dspp_frontend(dspp_device *dspp, uint32_t window_start, uint32_t window_end, uint32_t max_sequence);
+
+protected:
+ // required overrides
+ virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override;
+
+private:
+ // inlines
+
+ // internal helpers
+ bool describe_special(uint16_t op, opcode_desc &desc);
+ bool describe_branch(uint16_t op, opcode_desc &desc);
+ bool describe_complex_branch(uint16_t op, opcode_desc &desc);
+ bool describe_arithmetic(uint16_t op, opcode_desc &desc);
+
+ // internal state
+ dspp_device *m_dspp;
+};
+
+
+#endif /* DEVICES_CPU_DSPP_DSPPFE_H */