diff options
Diffstat (limited to 'src/mame/audio/iopspu.cpp')
-rw-r--r-- | src/mame/audio/iopspu.cpp | 204 |
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]; +} |