summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/dspp/dspp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/dspp/dspp.cpp')
-rw-r--r--src/devices/cpu/dspp/dspp.cpp2646
1 files changed, 2646 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
+}