summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/iopspu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/audio/iopspu.cpp')
-rw-r--r--src/mame/audio/iopspu.cpp204
1 files changed, 156 insertions, 48 deletions
diff --git a/src/mame/audio/iopspu.cpp b/src/mame/audio/iopspu.cpp
index 0e04e1283d9..bc60f19c48b 100644
--- a/src/mame/audio/iopspu.cpp
+++ b/src/mame/audio/iopspu.cpp
@@ -15,80 +15,152 @@ DEFINE_DEVICE_TYPE(SONYIOP_SPU, iop_spu_device, "iopspu", "Playstation 2 IOP SPU
iop_spu_device::iop_spu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SONYIOP_SPU, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
, m_iop(*this, finder_base::DUMMY_TAG)
+ , m_intc(*this, finder_base::DUMMY_TAG)
{
}
void iop_spu_device::device_start()
{
m_ram = std::make_unique<uint16_t[]>(2 * 1024 * 1024); // ?
+
+ if (!m_core[0].m_autodma_done_timer_hack)
+ m_core[0].m_autodma_done_timer_hack = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_spu_device::autodma_done_timer_hack), this), 0);
+
+ if (!m_core[1].m_autodma_done_timer_hack)
+ m_core[1].m_autodma_done_timer_hack = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_spu_device::autodma_done_timer_hack), this), (void*)1);
+
+ save_item(NAME(m_core[0].m_status));
+ save_item(NAME(m_core[0].m_start_port_addr));
+ save_item(NAME(m_core[0].m_curr_port_addr));
+ save_item(NAME(m_core[0].m_unknown_0x19a));
+ save_item(NAME(m_core[0].m_autodma_ctrl));
+ save_item(NAME(m_core[1].m_status));
+ save_item(NAME(m_core[1].m_start_port_addr));
+ save_item(NAME(m_core[1].m_curr_port_addr));
+ save_item(NAME(m_core[1].m_unknown_0x19a));
+ save_item(NAME(m_core[1].m_autodma_ctrl));
}
void iop_spu_device::device_reset()
{
- m_status = 0;
- m_start_port_addr = 0;
- m_curr_port_addr = 0;
- m_unknown_0x19a = 0;
+ m_core[0].m_status = 0;
+ m_core[0].m_start_port_addr = 0;
+ m_core[0].m_curr_port_addr = 0;
+ m_core[0].m_unknown_0x19a = 0;
+ m_core[0].m_autodma_ctrl = 0;
+ m_core[1].m_status = 0;
+ m_core[1].m_start_port_addr = 0;
+ m_core[1].m_curr_port_addr = 0;
+ m_core[1].m_unknown_0x19a = 0;
+ m_core[1].m_autodma_ctrl = 0;
+}
+
+void iop_spu_device::dma_write(int bank, uint32_t data)
+{
+ iop_spu_core_t &core = m_core[bank];
+ //m_ram[core.m_curr_port_addr] = (uint16_t)(data >> 16);
+ core.m_curr_port_addr++;
+ //m_ram[core.m_curr_port_addr] = (uint16_t)data;
+ core.m_curr_port_addr++;
+
+ if (core.m_curr_port_addr >= 0xfffff)
+ core.m_curr_port_addr = 0x2800 >> 1;
+
+ core.m_status &= ~STATUS_DMA_DONE;
+ core.m_status |= STATUS_DMA_ACTIVE;
+
+ if ((core.m_autodma_ctrl & (1 << bank)) && core.m_autodma_done_timer_hack->expire().is_never())
+ {
+ core.m_autodma_done_timer_hack->adjust(attotime::from_ticks(256, 48000), bank); // 256 halfwords * assumed 48kHz sampling rate
+ }
}
-void iop_spu_device::dma_write(uint32_t data)
+void iop_spu_device::dma_done(int bank)
{
- //m_ram[m_curr_port_addr] = (uint16_t)(data >> 16);
- m_curr_port_addr++;
- //m_ram[m_curr_port_addr] = (uint16_t)data;
- m_curr_port_addr++;
+ iop_spu_core_t &core = m_core[bank];
+ core.m_status |= STATUS_DMA_DONE;
+ core.m_status &= ~STATUS_DMA_ACTIVE;
+}
- m_status &= ~STATUS_DMA_DONE;
- m_status |= STATUS_DMA_ACTIVE;
+void iop_spu_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ // TODO
}
-void iop_spu_device::dma_done()
+TIMER_CALLBACK_MEMBER(iop_spu_device::autodma_done_timer_hack)
{
- m_status |= STATUS_DMA_DONE;
- m_status &= ~STATUS_DMA_ACTIVE;
+ m_core[param].m_autodma_done_timer_hack->adjust(attotime::never);
+ m_intc->raise_interrupt(iop_intc_device::INT_SPU);
}
-uint16_t iop_spu_device::port_read()
+uint16_t iop_spu_device::port_read(int bank)
{
- uint16_t ret = m_ram[m_curr_port_addr];
- m_curr_port_addr++;
+ iop_spu_core_t &core = m_core[bank];
+ const uint16_t ret = m_ram[core.m_curr_port_addr];
+ core.m_curr_port_addr++;
+ if (core.m_curr_port_addr >= 0xfffff)
+ core.m_curr_port_addr = 0x2800 >> 1;
return ret;
}
-void iop_spu_device::port_write(uint16_t data)
+void iop_spu_device::port_write(int bank, uint16_t data)
{
- m_ram[m_curr_port_addr] = data;
- m_curr_port_addr++;
+ iop_spu_core_t &core = m_core[bank];
+ m_ram[core.m_curr_port_addr] = data;
+ core.m_curr_port_addr++;
+ if (core.m_curr_port_addr >= 0xfffff)
+ core.m_curr_port_addr = 0x2800 >> 1;
}
READ16_MEMBER(iop_spu_device::read)
{
- uint32_t ret = 0;
+ return reg_read(BIT(offset, 9), (offset << 1) & 0x3ff, mem_mask);
+}
+
+uint16_t iop_spu_device::reg_read(int bank, uint32_t offset, uint16_t mem_mask)
+{
+ iop_spu_core_t &core = m_core[bank];
+ uint16_t ret = 0;
+
+ if (offset < 0x180)
+ {
+ const uint32_t reg = offset & 0xf;
+ ret = core.m_voices[offset >> 4].read(reg);
+ logerror("%s %d: Voice read: Unknown offset %d (%04x & %04x)\n", machine().describe_context(), bank, reg, ret, mem_mask);
+ return ret;
+ }
+
switch (offset)
{
- case 0x19a/2:
- ret = m_unknown_0x19a;
- logerror("%s: read: Unknown 0x19a (%04x & %04x)\n", machine().describe_context(), ret, mem_mask);
+ case 0x19a:
+ ret = core.m_unknown_0x19a;
+ logerror("%s %d: read: Unknown 0x19a (%04x & %04x)\n", machine().describe_context(), bank, ret, mem_mask);
break;
- case 0x1a8/2:
- ret = (uint16_t)(m_start_port_addr >> 16);
- logerror("%s: read: PORT_ADDR_HI: %04x & %04x\n", machine().describe_context(), ret, mem_mask);
+ case 0x1a8:
+ ret = (uint16_t)(core.m_start_port_addr >> 16);
+ logerror("%s %d: read: PORT_ADDR_HI: %04x & %04x\n", machine().describe_context(), bank, ret, mem_mask);
break;
- case 0x1aa/2:
- ret = (uint16_t)m_start_port_addr;
- logerror("%s: read: PORT_ADDR_LO: %04x & %04x\n", machine().describe_context(), ret, mem_mask);
+ case 0x1aa:
+ ret = (uint16_t)core.m_start_port_addr;
+ logerror("%s %d: read: PORT_ADDR_LO: %04x & %04x\n", machine().describe_context(), bank, ret, mem_mask);
break;
- case 0x344/2:
- ret = m_status;
- logerror("%s: read: STATUS: %04x & %04x\n", machine().describe_context(), ret, mem_mask);
+ case 0x1b0:
+ ret = core.m_autodma_ctrl;
+ logerror("%s %d: read: Auto DMA control: %04x & %04x\n", machine().describe_context(), bank, ret, mem_mask);
+ break;
+
+ case 0x344:
+ ret = core.m_status;
+ logerror("%s %d: read: STATUS: %04x & %04x\n", machine().describe_context(), bank, ret, mem_mask);
break;
default:
- logerror("%s: read: Unknown %08x (%04x)\n", machine().describe_context(), 0x1f900000 + (offset << 1), mem_mask);
+ logerror("%s %d: read: Unknown %08x (%04x)\n", machine().describe_context(), bank, 0x1f900000 + (offset << 1) + (bank << 10), mem_mask);
break;
}
return ret;
@@ -96,29 +168,65 @@ READ16_MEMBER(iop_spu_device::read)
WRITE16_MEMBER(iop_spu_device::write)
{
+ reg_write(BIT(offset, 9), (offset << 1) & 0x3ff, data, mem_mask);
+}
+
+void iop_spu_device::reg_write(int bank, uint32_t offset, uint16_t data, uint16_t mem_mask)
+{
+ iop_spu_core_t &core = m_core[bank];
+
+ if (offset < 0x180)
+ {
+ const uint32_t reg = offset & 0xf;
+ logerror("%s %d: Voice write: Unknown offset %d = %04x & %04x\n", machine().describe_context(), bank, reg, data, mem_mask);
+ core.m_voices[offset >> 4].write(reg, data);
+ return;
+ }
+
switch (offset)
{
- case 0x19a/2:
- logerror("%s: write: Unknown 0x19a = %04x & %04x\n", machine().describe_context(), data, mem_mask);
- m_unknown_0x19a = data;
+ case 0x19a:
+ logerror("%s %d: write: Unknown 0x19a = %04x & %04x\n", machine().describe_context(), bank, data, mem_mask);
+ if (BIT(data, 15)) // Reset?
+ {
+ data &= 0x7fff;
+ core.m_status = 0;
+ core.m_autodma_ctrl = 0;
+ }
+ core.m_unknown_0x19a = data;
break;
- case 0x1a8/2:
- logerror("%s: write: PORT_ADDR_HI: %04x & %04x\n", machine().describe_context(), data, mem_mask);
- m_start_port_addr &= ~0x000f0000;
- m_start_port_addr |= ((uint32_t)data << 16) & 0x000f0000;
- m_curr_port_addr = m_start_port_addr;
+ case 0x1a8:
+ logerror("%s %d: write: PORT_ADDR_HI: %04x & %04x\n", machine().describe_context(), bank, data, mem_mask);
+ core.m_start_port_addr &= ~0x000f0000;
+ core.m_start_port_addr |= ((uint32_t)data << 16) & 0x000f0000;
+ core.m_curr_port_addr = core.m_start_port_addr;
break;
- case 0x1aa/2:
- logerror("%s: write: PORT_ADDR_LO: %04x & %04x\n", machine().describe_context(), data, mem_mask);
- m_start_port_addr &= ~0x0000ffff;
- m_start_port_addr |= data;
- m_curr_port_addr = m_start_port_addr;
+ case 0x1aa:
+ logerror("%s %d: write: PORT_ADDR_LO: %04x & %04x\n", machine().describe_context(), bank, data, mem_mask);
+ core.m_start_port_addr &= ~0x0000ffff;
+ core.m_start_port_addr |= data;
+ core.m_curr_port_addr = core.m_start_port_addr;
break;
+ case 0x1b0:
+ logerror("%s %d: write: Auto DMA control: %04x & %04x\n", machine().describe_context(), bank, data, mem_mask);
+ core.m_autodma_ctrl = data;
+ break;
+
default:
- logerror("%s: write: Unknown %08x = %04x & %04x\n", machine().describe_context(), 0x1f900000 + (offset << 1), data, mem_mask);
+ logerror("%s %d: write: Unknown %08x = %04x & %04x\n", machine().describe_context(), bank, 0x1f900000 + (offset << 1) + (bank << 10), data, mem_mask);
break;
}
}
+
+void iop_spu_device::voice_t::write(uint32_t offset, uint16_t data)
+{
+ m_unknown[(offset >> 1) & 7] = data;
+}
+
+uint16_t iop_spu_device::voice_t::read(uint32_t offset)
+{
+ return m_unknown[(offset >> 1) & 7];
+}