diff options
Diffstat (limited to 'src/mame/machine/hpc3.cpp')
-rw-r--r-- | src/mame/machine/hpc3.cpp | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/src/mame/machine/hpc3.cpp b/src/mame/machine/hpc3.cpp new file mode 100644 index 00000000000..956edffda90 --- /dev/null +++ b/src/mame/machine/hpc3.cpp @@ -0,0 +1,577 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/********************************************************************** + + SGI HPC3 "High-performance Peripheral Controller" emulation + +**********************************************************************/ + +#include "emu.h" +#include "machine/hpc3.h" + +DEFINE_DEVICE_TYPE(SGI_HPC3, hpc3_device, "hpc3", "SGI HPC3") + +hpc3_device::hpc3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SGI_HPC3, tag, owner, clock) + , m_maincpu(*this, finder_base::DUMMY_TAG) + , m_wd33c93(*this, finder_base::DUMMY_TAG) + , m_ioc2(*this, finder_base::DUMMY_TAG) + , m_mainram(*this, ":mainram") + , m_unkpbus0(*this, ":unkpbus0") +{ +} + +#define VERBOSE_LEVEL ( 0 ) + +inline void ATTR_PRINTF(3,4) hpc3_device::verboselog(int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror("%s: %s", machine().describe_context(), buf); + } +} + +void hpc3_device::device_start() +{ +} + +void hpc3_device::device_reset() +{ + m_enetr_nbdp = 0x80000000; + m_enetr_cbp = 0x80000000; + m_pbus_dma.m_active = 0; +} + +void hpc3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_DMA: + do_dma(ptr, param); + break; + default: + assert_always(false, "Unknown id in hpc3_device::device_timer"); + } +} + +TIMER_CALLBACK_MEMBER(hpc3_device::do_dma) +{ + timer_set(attotime::never, TIMER_DMA); +#if 0 + if( m_pbus_dma.m_active ) + { + uint16_t temp16 = ( m_mainram[(m_pbus_dma.m_cur_ptr - 0x08000000)/4] & 0xffff0000 ) >> 16; + int16_t stemp16 = (int16_t)((temp16 >> 8) | (temp16 << 8)); + + m_dac->write_signed16(stemp16); + + m_pbus_dma.m_cur_ptr += 4; + + m_pbus_dma.m_words_left -= 4; + if( m_pbus_dma.m_words_left == 0 ) + { + if( m_pbus_dma.m_next_ptr != 0 ) + { + m_pbus_dma.m_desc_ptr = m_pbus_dma.m_next_ptr; + m_pbus_dma.m_cur_ptr = m_mainram[(m_pbus_dma.m_desc_ptr - 0x08000000)/4]; + m_pbus_dma.m_words_left = m_mainram[(m_pbus_dma.m_desc_ptr - 0x08000000)/4+1]; + m_pbus_dma.m_next_ptr = m_mainram[(m_pbus_dma.m_desc_ptr - 0x08000000)/4+2]; + } + else + { + m_pbus_dma.m_active = 0; + return; + } + } + timer_set(attotime::from_hz(44100), TIMER_DMA); + } +#endif +} + +READ32_MEMBER(hpc3_device::hd_enet_r) +{ + switch( offset ) + { + case 0x0004/4: + //verboselog((machine, 0, "HPC3 SCSI0DESC Read: %08x (%08x): %08x\n", 0x1fb90000 + ( offset << 2), mem_mask, m_scsi0_desc ); + return m_scsi0_desc; + case 0x1004/4: + //verboselog((machine, 0, "HPC3 SCSI0DMACTRL Read: %08x (%08x): %08x\n", 0x1fb90000 + ( offset << 2), mem_mask, m_scsi0_dma_ctrl ); + return m_scsi0_dma_ctrl; + case 0x4000/4: + //verboselog((machine, 2, "HPC3 ENETR CBP Read: %08x (%08x): %08x\n", 0x1fb90000 + ( offset << 2), mem_mask, m_enetr_nbdp ); + return m_enetr_cbp; + case 0x4004/4: + //verboselog((machine, 2, "HPC3 ENETR NBDP Read: %08x (%08x): %08x\n", 0x1fb90000 + ( offset << 2), mem_mask, m_enetr_nbdp ); + return m_enetr_nbdp; + default: + //verboselog((machine, 0, "Unknown HPC3 ENET/HDx Read: %08x (%08x)\n", 0x1fb90000 + ( offset << 2 ), mem_mask ); + return 0; + } +} + +WRITE32_MEMBER(hpc3_device::hd_enet_w) +{ + switch( offset ) + { + case 0x0004/4: + //verboselog((machine, 2, "HPC3 SCSI0DESC Write: %08x\n", data ); + m_scsi0_desc = data; + break; + case 0x1004/4: + //verboselog((machine, 2, "HPC3 SCSI0DMACTRL Write: %08x\n", data ); + m_scsi0_dma_ctrl = data; + break; + case 0x4000/4: + //verboselog((machine, 2, "HPC3 ENETR CBP Write: %08x\n", data ); + m_enetr_cbp = data; + break; + case 0x4004/4: + //verboselog((machine, 2, "HPC3 ENETR NBDP Write: %08x\n", data ); + m_enetr_nbdp = data; + break; + default: + //verboselog((machine, 0, "Unknown HPC3 ENET/HDx write: %08x (%08x): %08x\n", 0x1fb90000 + ( offset << 2 ), mem_mask, data ); + break; + } +} + +READ32_MEMBER(hpc3_device::hd0_r) +{ + switch( offset ) + { + case 0x0000/4: + case 0x4000/4: +// //verboselog((machine, 2, "HPC3 HD0 Status Read: %08x (%08x): %08x\n", 0x1fb90000 + ( offset << 2), mem_mask, nHPC3_hd0_regs[0x17] ); + if (ACCESSING_BITS_0_7) + { + return m_wd33c93->read( space, 0 ); + } + else + { + return 0; + } + case 0x0004/4: + case 0x4004/4: +// //verboselog((machine, 2, "HPC3 HD0 Register Read: %08x (%08x): %08x\n", 0x1fb90000 + ( offset << 2), mem_mask, nHPC3_hd0_regs[nHPC3_hd0_register] ); + if (ACCESSING_BITS_0_7) + { + return m_wd33c93->read( space, 1 ); + } + else + { + return 0; + } + default: + //verboselog((machine, 0, "Unknown HPC3 HD0 Read: %08x (%08x) [%x] PC=%x\n", 0x1fbc0000 + ( offset << 2 ), mem_mask, offset, m_maincpu->pc() ); + return 0; + } +} + +WRITE32_MEMBER(hpc3_device::hd0_w) +{ + switch( offset ) + { + case 0x0000/4: + case 0x4000/4: +// //verboselog((machine, 2, "HPC3 HD0 Register Select Write: %08x\n", data ); + if (ACCESSING_BITS_0_7) + { + m_wd33c93->write( space, 0, data & 0x000000ff ); + } + break; + case 0x0004/4: + case 0x4004/4: +// //verboselog((machine, 2, "HPC3 HD0 Register %d Write: %08x\n", nHPC3_hd0_register, data ); + if (ACCESSING_BITS_0_7) + { + m_wd33c93->write( space, 1, data & 0x000000ff ); + } + break; + default: + //verboselog((machine, 0, "Unknown HPC3 HD0 Write: %08x (%08x): %08x\n", 0x1fbc0000 + ( offset << 2 ), mem_mask, data ); + break; + } +} + + +READ32_MEMBER(hpc3_device::pbus4_r) +{ + switch( offset ) + { + case 0x0004/4: + //verboselog((machine, 2, "HPC3 PBUS4 Unknown 0 Read: (%08x): %08x\n", mem_mask, m_unk0 ); + return m_unk0; + case 0x000c/4: + //verboselog((machine, 2, "Interrupt Controller(?) Read: (%08x): %08x\n", mem_mask, m_ic_unk0 ); + return m_ic_unk0; + case 0x0014/4: + //verboselog((machine, 2, "HPC3 PBUS4 Unknown 1 Read: (%08x): %08x\n", mem_mask, m_unk1 ); + return m_unk1; + default: + //verboselog((machine, 0, "Unknown HPC3 PBUS4 Read: %08x (%08x)\n", 0x1fbd9000 + ( offset << 2 ), mem_mask ); + return 0; + } +} + +WRITE32_MEMBER(hpc3_device::pbus4_w) +{ + switch( offset ) + { + case 0x0004/4: + //verboselog((machine, 2, "HPC3 PBUS4 Unknown 0 Write: %08x (%08x)\n", data, mem_mask ); + m_unk0 = data; + break; + case 0x000c/4: + //verboselog((machine, 2, "Interrupt Controller(?) Write: (%08x): %08x\n", mem_mask, data ); + m_ic_unk0 = data; + break; + case 0x0014/4: + //verboselog((machine, 2, "HPC3 PBUS4 Unknown 1 Write: %08x (%08x)\n", data, mem_mask ); + m_unk1 = data; + break; + default: + //verboselog((machine, 0, "Unknown HPC3 PBUS4 Write: %08x (%08x): %08x\n", 0x1fbd9000 + ( offset << 2 ), mem_mask, data ); + break; + } +} + +READ32_MEMBER(hpc3_device::pbusdma_r) +{ + //uint32_t channel = offset / (0x2000/4); + //verboselog((machine(), 0, "PBUS DMA Channel %d Read: 0x%08x (%08x)\n", channel, 0x1fb80000 + offset*4, mem_mask ); + return 0; +} + +WRITE32_MEMBER(hpc3_device::pbusdma_w) +{ + uint32_t channel = offset / (0x2000/4); + + switch( offset & 0x07ff ) + { + case 0x0000/4: + //verboselog((machine, 0, "PBUS DMA Channel %d Buffer Pointer Write: 0x%08x\n", channel, data ); + return; + case 0x0004/4: + //verboselog((machine, 0, "PBUS DMA Channel %d Descriptor Pointer Write: 0x%08x\n", channel, data ); + if( channel == 1 ) + { + m_pbus_dma.m_desc_ptr = data; + m_pbus_dma.m_cur_ptr = m_mainram[(m_pbus_dma.m_desc_ptr - 0x08000000)/4]; + m_pbus_dma.m_words_left = m_mainram[(m_pbus_dma.m_desc_ptr - 0x08000000)/4+1]; + m_pbus_dma.m_next_ptr = m_mainram[(m_pbus_dma.m_desc_ptr - 0x08000000)/4+2]; + //verboselog((machine, 0, "nPBUS_DMA_DescPtr = %08x\n", m_pbus_dma.m_desc_ptr ); + //verboselog((machine, 0, "nPBUS_DMA_CurPtr = %08x\n", m_pbus_dma.m_cur_ptr ); + //verboselog((machine, 0, "nPBUS_DMA_WordsLeft = %08x\n", m_pbus_dma.m_words_left ); + //verboselog((machine, 0, "nPBUS_DMA_NextPtr = %08x\n", m_pbus_dma.m_next_ptr ); + } + return; + case 0x1000/4: + //verboselog((machine, 0, "PBUS DMA Channel %d Control Register Write: 0x%08x\n", channel, data ); + if( data & PBUS_CTRL_ENDIAN ) + { + //verboselog((machine, 0, " Little Endian\n" ); + } + else + { + //verboselog((machine, 0, " Big Endian\n" ); + } + if( data & PBUS_CTRL_RECV ) + { + //verboselog((machine, 0, " RX DMA\n" ); + } + else + { + //verboselog((machine, 0, " TX DMA\n" ); + } + if( data & PBUS_CTRL_FLUSH ) + { + //verboselog((machine, 0, " Flush for RX\n" ); + } + if( data & PBUS_CTRL_DMASTART ) + { + //verboselog((machine, 0, " Start DMA\n" ); + } + if( data & PBUS_CTRL_LOAD_EN ) + { + //verboselog((machine, 0, " Load Enable\n" ); + } + //verboselog((machine, 0, " High Water Mark: %04x bytes\n", ( data & PBUS_CTRL_HIGHWATER ) >> 8 ); + //verboselog((machine, 0, " FIFO Begin: Row %04x\n", ( data & PBUS_CTRL_FIFO_BEG ) >> 16 ); + //verboselog((machine, 0, " FIFO End: Rowe %04x\n", ( data & PBUS_CTRL_FIFO_END ) >> 24 ); + if( ( data & PBUS_CTRL_DMASTART ) || ( data & PBUS_CTRL_LOAD_EN ) ) + { + timer_set(attotime::from_hz(44100), TIMER_DMA); + m_pbus_dma.m_active = 1; + } + return; + } + //verboselog((machine, 0, "Unknown PBUS DMA Channel %d Write: 0x%08x: 0x%08x (%08x)\n", channel, 0x1fb80000 + offset*4, data, mem_mask ); +} + +READ32_MEMBER(hpc3_device::unkpbus0_r) +{ + return 0; + ////verboselog((machine(), 0, "Unknown PBUS Read: 0x%08x (%08x)\n", 0x1fbc8000 + offset*4, mem_mask ); + //return m_unkpbus0[offset]; +} + +WRITE32_MEMBER(hpc3_device::unkpbus0_w) +{ + ////verboselog((machine(), 0, "Unknown PBUS Write: 0x%08x = 0x%08x (%08x)\n", 0x1fbc8000 + offset*4, data, mem_mask ); + //COMBINE_DATA(&m_unkpbus0[offset]); +} + +void hpc3_device::dump_chain(address_space &space, uint32_t ch_base) +{ + logerror("node: %08x %08x %08x (len = %x)\n", space.read_dword(ch_base), space.read_dword(ch_base+4), space.read_dword(ch_base+8), space.read_dword(ch_base+4) & 0x3fff); + + if ((space.read_dword(ch_base+8) != 0) && !(space.read_dword(ch_base+4) & 0x80000000)) + { + dump_chain(space, space.read_dword(ch_base+8)); + } +} + +WRITE_LINE_MEMBER(hpc3_device::scsi_irq) +{ + address_space &space = m_maincpu->space(AS_PROGRAM); + + if (state) + { + if (m_wd33c93->get_dma_count()) + { + logerror("m_wd33c93->get_dma_count() is %d\n", m_wd33c93->get_dma_count() ); + if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENABLE) + { + if (m_scsi0_dma_ctrl & HPC3_DMACTRL_IRQ) logerror("IP22: Unhandled SCSI DMA IRQ\n"); + } + + // HPC3 DMA: host to device + if ((m_scsi0_dma_ctrl & HPC3_DMACTRL_ENABLE) && (m_scsi0_dma_ctrl & HPC3_DMACTRL_DIR)) + { + uint32_t wptr, tmpword; + int words, dptr, twords; + + words = m_wd33c93->get_dma_count(); + words /= 4; + + wptr = space.read_dword(m_scsi0_desc); + m_scsi0_desc += words*4; + dptr = 0; + + logerror("DMA to device: %d words @ %x\n", words, wptr); + + dump_chain(space, m_scsi0_desc); + + if (words <= (512/4)) + { + // one-shot + //m_wd33c93->dma_read_data(m_wd33c93->get_dma_count(), m_dma_buffer); + + while (words) + { + tmpword = space.read_dword(wptr); + + if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENDIAN) + { + m_dma_buffer[dptr+3] = (tmpword>>24)&0xff; + m_dma_buffer[dptr+2] = (tmpword>>16)&0xff; + m_dma_buffer[dptr+1] = (tmpword>>8)&0xff; + m_dma_buffer[dptr] = tmpword&0xff; + } + else + { + m_dma_buffer[dptr] = (tmpword>>24)&0xff; + m_dma_buffer[dptr+1] = (tmpword>>16)&0xff; + m_dma_buffer[dptr+2] = (tmpword>>8)&0xff; + m_dma_buffer[dptr+3] = tmpword&0xff; + } + + wptr += 4; + dptr += 4; + words--; + } + + words = m_wd33c93->get_dma_count(); + m_wd33c93->dma_write_data(words, m_dma_buffer); + } + else + { + while (words) + { + //m_wd33c93->dma_read_data(512, m_dma_buffer); + twords = 512/4; + m_scsi0_desc += 512; + dptr = 0; + + while (twords) + { + tmpword = space.read_dword(wptr); + + if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENDIAN) + { + m_dma_buffer[dptr+3] = (tmpword>>24)&0xff; + m_dma_buffer[dptr+2] = (tmpword>>16)&0xff; + m_dma_buffer[dptr+1] = (tmpword>>8)&0xff; + m_dma_buffer[dptr] = tmpword&0xff; + } + else + { + m_dma_buffer[dptr] = (tmpword>>24)&0xff; + m_dma_buffer[dptr+1] = (tmpword>>16)&0xff; + m_dma_buffer[dptr+2] = (tmpword>>8)&0xff; + m_dma_buffer[dptr+3] = tmpword&0xff; + } + + wptr += 4; + dptr += 4; + twords--; + } + + m_wd33c93->dma_write_data(512, m_dma_buffer); + + words -= (512/4); + } + } + + // clear DMA on the controller too + m_wd33c93->clear_dma(); +#if 0 + uint32_t dptr, tmpword; + uint32_t bc = space.read_dword(m_scsi0_desc + 4); + uint32_t rptr = space.read_dword(m_scsi0_desc); + int length = bc & 0x3fff; + int xie = (bc & 0x20000000) ? 1 : 0; + int eox = (bc & 0x80000000) ? 1 : 0; + + dump_chain(space, m_scsi0_desc); + + logerror("%s DMA to device: length %x xie %d eox %d\n", machine().describe_context().c_str(), length, xie, eox); + + if (length <= 0x4000) + { + dptr = 0; + while (length > 0) + { + tmpword = space.read_dword(rptr); + if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENDIAN) + { + m_dma_buffer[dptr+3] = (tmpword>>24)&0xff; + m_dma_buffer[dptr+2] = (tmpword>>16)&0xff; + m_dma_buffer[dptr+1] = (tmpword>>8)&0xff; + m_dma_buffer[dptr] = tmpword&0xff; + } + else + { + m_dma_buffer[dptr] = (tmpword>>24)&0xff; + m_dma_buffer[dptr+1] = (tmpword>>16)&0xff; + m_dma_buffer[dptr+2] = (tmpword>>8)&0xff; + m_dma_buffer[dptr+3] = tmpword&0xff; + } + + dptr += 4; + rptr += 4; + length -= 4; + } + + length = space.read_dword(m_scsi0_desc+4) & 0x3fff; + m_wd33c93->write_data(length, m_dma_buffer); + + // clear DMA on the controller too + m_wd33c93->clear_dma(); + } + else + { + logerror("IP22: overly large host to device transfer, can't handle!\n"); + } +#endif + } + + // HPC3 DMA: device to host + if ((m_scsi0_dma_ctrl & HPC3_DMACTRL_ENABLE) && !(m_scsi0_dma_ctrl & HPC3_DMACTRL_DIR)) + { + uint32_t wptr, tmpword; + int words, sptr, twords; + + words = m_wd33c93->get_dma_count(); + words /= 4; + + wptr = space.read_dword(m_scsi0_desc); + sptr = 0; + +// osd_printf_info("DMA from device: %d words @ %x\n", words, wptr); + + dump_chain(space, m_scsi0_desc); + + if (words <= (1024/4)) + { + // one-shot + m_wd33c93->dma_read_data(m_wd33c93->get_dma_count(), m_dma_buffer); + + while (words) + { + if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENDIAN) + { + tmpword = m_dma_buffer[sptr+3]<<24 | m_dma_buffer[sptr+2]<<16 | m_dma_buffer[sptr+1]<<8 | m_dma_buffer[sptr]; + } + else + { + tmpword = m_dma_buffer[sptr]<<24 | m_dma_buffer[sptr+1]<<16 | m_dma_buffer[sptr+2]<<8 | m_dma_buffer[sptr+3]; + } + + space.write_dword(wptr, tmpword); + wptr += 4; + sptr += 4; + words--; + } + } + else + { + while (words) + { + m_wd33c93->dma_read_data(512, m_dma_buffer); + twords = 512/4; + sptr = 0; + + while (twords) + { + if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENDIAN) + { + tmpword = m_dma_buffer[sptr+3]<<24 | m_dma_buffer[sptr+2]<<16 | m_dma_buffer[sptr+1]<<8 | m_dma_buffer[sptr]; + } + else + { + tmpword = m_dma_buffer[sptr]<<24 | m_dma_buffer[sptr+1]<<16 | m_dma_buffer[sptr+2]<<8 | m_dma_buffer[sptr+3]; + } + space.write_dword(wptr, tmpword); + + wptr += 4; + sptr += 4; + twords--; + } + + words -= (512/4); + } + } + + // clear DMA on the controller too + m_wd33c93->clear_dma(); + } + } + + // clear HPC3 DMA active flag + m_scsi0_dma_ctrl &= ~HPC3_DMACTRL_ENABLE; + + // set the interrupt + m_ioc2->raise_local0_irq(ioc2_device::INT3_LOCAL0_SCSI0); + } + else + { + m_ioc2->lower_local0_irq(ioc2_device::INT3_LOCAL0_SCSI0); + } +} |