-indy_indigo2: General cleanup, device-ified HAL2 and HPC3, and moved HAL2, HPC3, and IOC2 devices into their own files. [Ryan Holtz]

This commit is contained in:
mooglyguy 2018-04-23 23:04:52 +02:00
parent 1b30e55f6b
commit 31579ede9a
8 changed files with 1647 additions and 1317 deletions

View File

@ -2908,6 +2908,12 @@ createMESSProjects(_target, _subtarget, "sgi")
files {
MAME_DIR .. "src/mame/machine/sgi.cpp",
MAME_DIR .. "src/mame/machine/sgi.h",
MAME_DIR .. "src/mame/machine/hal2.cpp",
MAME_DIR .. "src/mame/machine/hal2.h",
MAME_DIR .. "src/mame/machine/hpc3.cpp",
MAME_DIR .. "src/mame/machine/hpc3.h",
MAME_DIR .. "src/mame/machine/ioc2.cpp",
MAME_DIR .. "src/mame/machine/ioc2.h",
MAME_DIR .. "src/mame/drivers/iris3130.cpp",
MAME_DIR .. "src/mame/drivers/4dpi.cpp",
MAME_DIR .. "src/mame/drivers/indigo.cpp",

File diff suppressed because it is too large Load Diff

175
src/mame/machine/hal2.cpp Normal file
View File

@ -0,0 +1,175 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/**********************************************************************
SGI HAL2 Audio Controller emulation
**********************************************************************/
#include "emu.h"
#include "machine/hal2.h"
DEFINE_DEVICE_TYPE(SGI_HAL2, hal2_device, "hal2", "SGI HAL2")
hal2_device::hal2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SGI_HAL2, tag, owner, clock)
, m_iar(0)
, m_idr{ 0, 0, 0, 0 }
{
}
#define VERBOSE_LEVEL ( 0 )
inline void ATTR_PRINTF(3,4) hal2_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 hal2_device::device_start()
{
}
void hal2_device::device_reset()
{
m_iar = 0;
memset(m_idr, 0, sizeof(uint32_t) * 4);
}
READ32_MEMBER(hal2_device::read)
{
switch( offset )
{
case STATUS_REG:
//verboselog((machine, 0, "HAL2 Status read: 0x0004\n" );
return 0x0004;
case REVISION_REG:
//verboselog((machine, 0, "HAL2 Revision read: 0x4011\n" );
return 0x4011;
}
//verboselog((machine, 0, "Unknown HAL2 read: 0x%08x (%08x)\n", 0x1fbd8000 + offset*4, mem_mask );
return 0;
}
WRITE32_MEMBER(hal2_device::write)
{
switch (offset)
{
case STATUS_REG:
//verboselog((machine, 0, "HAL2 Status Write: 0x%08x (%08x)\n", data, mem_mask );
if (data & ISR_GLOBAL_RESET)
{
//verboselog((machine, 0, " HAL2 Global Reset\n" );
}
if (data & ISR_CODEC_RESET)
{
//verboselog((machine, 0, " HAL2 Codec Reset\n" );
}
break;
case INDIRECT_ADDRESS_REG:
//verboselog((machine, 0, "HAL2 Indirect Address Register Write: 0x%08x (%08x)\n", data, mem_mask );
m_iar = data;
switch (data & IAR_TYPE)
{
case 0x1000:
//verboselog((machine, 0, " DMA Port\n" );
switch (data & IAR_NUM)
{
case 0x0100:
//verboselog((machine, 0, " Synth In\n" );
break;
case 0x0200:
//verboselog((machine, 0, " AES In\n" );
break;
case 0x0300:
//verboselog((machine, 0, " AES Out\n" );
break;
case 0x0400:
//verboselog((machine, 0, " DAC Out\n" );
break;
case 0x0500:
//verboselog((machine, 0, " ADC Out\n" );
break;
case 0x0600:
//verboselog((machine, 0, " Synth Control\n" );
break;
}
break;
case 0x2000:
//verboselog((machine, 0, " Bresenham\n" );
switch (data & IAR_NUM)
{
case 0x0100:
//verboselog((machine, 0, " Bresenham Clock Gen 1\n" );
break;
case 0x0200:
//verboselog((machine, 0, " Bresenham Clock Gen 2\n" );
break;
case 0x0300:
//verboselog((machine, 0, " Bresenham Clock Gen 3\n" );
break;
}
break;
case 0x3000:
//verboselog((machine, 0, " Unix Timer\n" );
switch (data & IAR_NUM)
{
case 0x0100:
//verboselog((machine, 0, " Unix Timer\n" );
break;
}
break;
case 0x9000:
//verboselog((machine, 0, " Global DMA Control\n" );
switch (data & IAR_NUM)
{
case 0x0100:
//verboselog((machine, 0, " DMA Control\n" );
break;
}
break;
}
switch (data & IAR_ACCESS_SEL)
{
case 0x0000:
//verboselog((machine, 0, " Write\n" );
break;
case 0x0080:
//verboselog((machine, 0, " Read\n" );
break;
}
//verboselog((machine, 0, " Parameter: %01x\n", ( data & IAR_PARAM ) >> 2 );
return;
case INDIRECT_DATA0_REG:
//verboselog((machine, 0, "HAL2 Indirect Data Register 0 Write: 0x%08x (%08x)\n", data, mem_mask );
m_idr[0] = data;
return;
case INDIRECT_DATA1_REG:
//verboselog((machine, 0, "HAL2 Indirect Data Register 1 Write: 0x%08x (%08x)\n", data, mem_mask );
m_idr[1] = data;
return;
case INDIRECT_DATA2_REG:
//verboselog((machine, 0, "HAL2 Indirect Data Register 2 Write: 0x%08x (%08x)\n", data, mem_mask );
m_idr[2] = data;
return;
case INDIRECT_DATA3_REG:
//verboselog((machine, 0, "HAL2 Indirect Data Register 3 Write: 0x%08x (%08x)\n", data, mem_mask );
m_idr[3] = data;
return;
}
//verboselog((machine, 0, "Unknown HAL2 write: 0x%08x: 0x%08x (%08x)\n", 0x1fbd8000 + offset*4, data, mem_mask );
}

66
src/mame/machine/hal2.h Normal file
View File

@ -0,0 +1,66 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/**********************************************************************
SGI HAL2 Audio Controller emulation
**********************************************************************/
#ifndef MAME_MACHINE_HAL2_H
#define MAME_MACHINE_HAL2_H
#pragma once
#define MCFG_SGI_HAL2_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, SGI_HAL2, 0)
class hal2_device : public device_t
{
public:
hal2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_WRITE32_MEMBER( write );
DECLARE_READ32_MEMBER( read );
protected:
virtual void device_start() override;
virtual void device_reset() override;
enum
{
IAR_TYPE = 0xf000,
IAR_NUM = 0x0f00,
IAR_ACCESS_SEL = 0x0080,
IAR_PARAM = 0x000c,
IAR_RB_INDEX = 0x0003,
};
enum
{
ISR_TSTATUS = 0x01,
ISR_USTATUS = 0x02,
ISR_QUAD_MODE = 0x04,
ISR_GLOBAL_RESET = 0x08,
ISR_CODEC_RESET = 0x10,
};
enum
{
STATUS_REG = 0x0010/4,
REVISION_REG = 0x0020/4,
INDIRECT_ADDRESS_REG = 0x0030/4,
INDIRECT_DATA0_REG = 0x0040/4,
INDIRECT_DATA1_REG = 0x0050/4,
INDIRECT_DATA2_REG = 0x0060/4,
INDIRECT_DATA3_REG = 0x0070/4,
};
uint32_t m_iar;
uint32_t m_idr[4];
inline void ATTR_PRINTF(3,4) verboselog(int n_level, const char *s_fmt, ... );
};
DECLARE_DEVICE_TYPE(SGI_HAL2, hal2_device)
#endif // MAME_MACHINE_HAL2_H

577
src/mame/machine/hpc3.cpp Normal file
View File

@ -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);
}
}

128
src/mame/machine/hpc3.h Normal file
View File

@ -0,0 +1,128 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/**********************************************************************
SGI HPC3 "High-performance Peripheral Controller" emulation
**********************************************************************/
#ifndef MAME_MACHINE_HPC3_H
#define MAME_MACHINE_HPC3_H
#pragma once
#include "cpu/mips/mips3.h"
#include "machine/ioc2.h"
#include "machine/wd33c93.h"
#define MCFG_SGI_HPC3_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, SGI_HPC3, 0)
#define MCFG_HPC3_CPU_TAG(cpu_tag) \
downcast<hpc3_device &>(*device).set_cpu_tag(("^" cpu_tag));
#define MCFG_HPC3_SCSI_TAG(scsi_tag) \
downcast<hpc3_device &>(*device).set_scsi_tag(("^" scsi_tag));
#define MCFG_HPC3_IOC2_TAG(ioc2_tag) \
downcast<hpc3_device &>(*device).set_ioc2_tag(("^" ioc2_tag));
class hpc3_device : public device_t
{
public:
hpc3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void set_cpu_tag(const char *tag) { m_maincpu.set_tag(tag); }
void set_scsi_tag(const char *tag) { m_wd33c93.set_tag(tag); }
void set_ioc2_tag(const char *tag) { m_ioc2.set_tag(tag); }
DECLARE_READ32_MEMBER(hd_enet_r);
DECLARE_WRITE32_MEMBER(hd_enet_w);
DECLARE_READ32_MEMBER(hd0_r);
DECLARE_WRITE32_MEMBER(hd0_w);
DECLARE_READ32_MEMBER(pbus4_r);
DECLARE_WRITE32_MEMBER(pbus4_w);
DECLARE_READ32_MEMBER(pbusdma_r);
DECLARE_WRITE32_MEMBER(pbusdma_w);
DECLARE_READ32_MEMBER(unkpbus0_r);
DECLARE_WRITE32_MEMBER(unkpbus0_w);
DECLARE_WRITE_LINE_MEMBER(scsi_irq);
TIMER_CALLBACK_MEMBER(do_dma);
protected:
void device_start() override;
void device_reset() override;
void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
void dump_chain(address_space &space, uint32_t ch_base);
struct pbus_dma_t
{
uint8_t m_active;
uint32_t m_cur_ptr;
uint32_t m_desc_ptr;
uint32_t m_next_ptr;
uint32_t m_words_left;
};
enum
{
TIMER_DMA
};
enum
{
PBUS_CTRL_ENDIAN = 0x00000002,
PBUS_CTRL_RECV = 0x00000004,
PBUS_CTRL_FLUSH = 0x00000008,
PBUS_CTRL_DMASTART = 0x00000010,
PBUS_CTRL_LOAD_EN = 0x00000020,
PBUS_CTRL_REALTIME = 0x00000040,
PBUS_CTRL_HIGHWATER = 0x0000ff00,
PBUS_CTRL_FIFO_BEG = 0x003f0000,
PBUS_CTRL_FIFO_END = 0x3f000000,
};
enum
{
PBUS_DMADESC_EOX = 0x80000000,
PBUS_DMADESC_EOXP = 0x40000000,
PBUS_DMADESC_XIE = 0x20000000,
PBUS_DMADESC_IPG = 0x00ff0000,
PBUS_DMADESC_TXD = 0x00008000,
PBUS_DMADESC_BC = 0x00003fff,
};
enum
{
HPC3_DMACTRL_IRQ = 0x01,
HPC3_DMACTRL_ENDIAN = 0x02,
HPC3_DMACTRL_DIR = 0x04,
HPC3_DMACTRL_ENABLE = 0x10,
};
required_device<mips3_device> m_maincpu;
required_device<wd33c93_device> m_wd33c93;
required_device<ioc2_device> m_ioc2;
required_shared_ptr<uint32_t> m_mainram;
required_shared_ptr<uint32_t> m_unkpbus0;
uint32_t m_enetr_nbdp;
uint32_t m_enetr_cbp;
uint32_t m_unk0;
uint32_t m_unk1;
uint32_t m_ic_unk0;
uint32_t m_scsi0_desc;
uint32_t m_scsi0_dma_ctrl;
pbus_dma_t m_pbus_dma;
uint8_t m_dma_buffer[4096];
inline void ATTR_PRINTF(3,4) verboselog(int n_level, const char *s_fmt, ... );
};
DECLARE_DEVICE_TYPE(SGI_HPC3, hpc3_device)
#endif // MAME_MACHINE_HAL2_H

432
src/mame/machine/ioc2.cpp Normal file
View File

@ -0,0 +1,432 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/**********************************************************************
SGI IOC2 I/O Controller emulation
**********************************************************************/
#include "emu.h"
#include "bus/rs232/rs232.h"
#include "machine/ioc2.h"
/*static*/ const char *ioc2_device::SCC_TAG = "scc";
/*static*/ const char *ioc2_device::PI1_TAG = "pi1";
/*static*/ const char *ioc2_device::KBDC_TAG = "kbdc";
/*static*/ const char *ioc2_device::PIT_TAG = "pit";
/*static*/ const char *ioc2_device::RS232A_TAG = "rs232a";
/*static*/ const char *ioc2_device::RS232B_TAG = "rs232b";
/*static*/ const XTAL ioc2_device::SCC_PCLK = XTAL(10'000'000);
/*static*/ const XTAL ioc2_device::SCC_RXA_CLK = XTAL(3'686'400); // Needs verification
/*static*/ const XTAL ioc2_device::SCC_TXA_CLK = XTAL(0);
/*static*/ const XTAL ioc2_device::SCC_RXB_CLK = XTAL(3'686'400); // Needs verification
/*static*/ const XTAL ioc2_device::SCC_TXB_CLK = XTAL(0);
DEFINE_DEVICE_TYPE(SGI_IOC2_GUINNESS, ioc2_guinness_device, "ioc2g", "SGI IOC2 (Guiness)")
DEFINE_DEVICE_TYPE(SGI_IOC2_FULL_HOUSE, ioc2_full_house_device, "ioc2f", "SGI IOC2 (Full House)")
ioc2_guinness_device::ioc2_guinness_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ioc2_guinness_device(mconfig, SGI_IOC2_GUINNESS, tag, owner, clock)
{
}
ioc2_full_house_device::ioc2_full_house_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ioc2_full_house_device(mconfig, SGI_IOC2_FULL_HOUSE, tag, owner, clock)
{
}
static INPUT_PORTS_START( front_panel )
PORT_START("panel_buttons")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Power") PORT_CHANGED_MEMBER(DEVICE_SELF, ioc2_device, power_button, 0)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Volume Down") PORT_CHANGED_MEMBER(DEVICE_SELF, ioc2_device, volume_down, 0)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Volume Up") PORT_CHANGED_MEMBER(DEVICE_SELF, ioc2_device, volume_up, 0)
INPUT_PORTS_END
ioport_constructor ioc2_device::device_input_ports() const
{
return INPUT_PORTS_NAME(front_panel);
}
MACHINE_CONFIG_START(ioc2_device::device_add_mconfig)
MCFG_SCC85230_ADD(SCC_TAG, SCC_PCLK, SCC_RXA_CLK.value(), SCC_TXA_CLK.value(), SCC_RXB_CLK.value(), SCC_TXB_CLK.value())
MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_DTRA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_dtr))
MCFG_Z80SCC_OUT_RTSA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_rts))
MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(RS232B_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_DTRB_CB(DEVWRITELINE(RS232B_TAG, rs232_port_device, write_dtr))
MCFG_Z80SCC_OUT_RTSB_CB(DEVWRITELINE(RS232B_TAG, rs232_port_device, write_rts))
MCFG_RS232_PORT_ADD(RS232A_TAG, default_rs232_devices, nullptr)
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC_TAG, scc85230_device, ctsa_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC_TAG, scc85230_device, dcda_w))
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC_TAG, scc85230_device, rxa_w))
MCFG_RS232_PORT_ADD(RS232B_TAG, default_rs232_devices, nullptr)
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC_TAG, scc85230_device, ctsb_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC_TAG, scc85230_device, dcdb_w))
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC_TAG, scc85230_device, rxb_w))
MCFG_DEVICE_ADD(PI1_TAG, PC_LPT, 0)
MCFG_DEVICE_ADD(KBDC_TAG, KBDC8042, 0)
MCFG_KBDC8042_KEYBOARD_TYPE(KBDC8042_PS2)
MCFG_KBDC8042_SYSTEM_RESET_CB(INPUTLINE("^maincpu", INPUT_LINE_RESET))
MCFG_DEVICE_ADD(PIT_TAG, PIT8254, 0)
MCFG_PIT8253_CLK0(1000000)
MCFG_PIT8253_CLK1(1000000)
MCFG_PIT8253_CLK2(1000000)
MCFG_PIT8253_OUT2_HANDLER(DEVWRITELINE(KBDC_TAG, kbdc8042_device, write_out2))
MACHINE_CONFIG_END
ioc2_device::ioc2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t id)
: device_t(mconfig, type, tag, owner, clock)
, m_maincpu(*this, finder_base::DUMMY_TAG)
, m_scc(*this, SCC_TAG)
, m_pi1(*this, PI1_TAG)
, m_kbdc(*this, KBDC_TAG)
, m_pit(*this, PIT_TAG)
, m_gen_ctrl_select_reg(0)
, m_gen_ctrl_reg(0)
, m_front_panel_reg(0)
, m_read_reg(0)
, m_dma_sel(0)
, m_reset_reg(0)
, m_write_reg(0)
, m_int3_local0_status_reg(0)
, m_int3_local0_mask_reg(0)
, m_int3_local1_status_reg(0)
, m_int3_local1_mask_reg(0)
, m_int3_map_status_reg(0)
, m_int3_map_mask0_reg(0)
, m_int3_map_mask1_reg(0)
, m_int3_map_pol_reg(0)
, m_int3_timer_clear_reg(0)
, m_int3_err_status_reg(0)
, m_par_read_cnt(0)
, m_par_cntl(0)
, m_system_id(id)
{
}
void ioc2_device::device_start()
{
m_front_panel_reg = FRONT_PANEL_POWER_STATE;
}
void ioc2_device::device_reset()
{
m_par_read_cnt = 0;
m_par_cntl = 0;
m_gen_ctrl_select_reg = 0;
m_gen_ctrl_reg = 0;
m_front_panel_reg = FRONT_PANEL_POWER_STATE;
m_read_reg = 0;
m_dma_sel = 0;
m_reset_reg = 0;
m_write_reg = 0;
m_int3_local0_status_reg = 0;
m_int3_local0_mask_reg = 0;
m_int3_local1_status_reg = 0;
m_int3_local1_mask_reg = 0;
m_int3_map_status_reg = 0;
m_int3_map_mask0_reg = 0;
m_int3_map_mask1_reg = 0;
m_int3_map_pol_reg = 0;
m_int3_timer_clear_reg = 0;
m_int3_err_status_reg = 0;
}
void ioc2_device::raise_local0_irq(uint8_t source_mask)
{
m_int3_local0_status_reg |= source_mask;
m_maincpu->set_input_line(MIPS3_IRQ0, (m_int3_local0_mask_reg & m_int3_local0_status_reg) != 0 ? ASSERT_LINE : CLEAR_LINE);
}
void ioc2_device::lower_local0_irq(uint8_t source_mask)
{
m_int3_local0_status_reg &= ~source_mask;
}
void ioc2_device::raise_local1_irq(uint8_t source_mask)
{
m_int3_local1_status_reg |= source_mask;
m_maincpu->set_input_line(MIPS3_IRQ1, (m_int3_local1_mask_reg & m_int3_local1_status_reg) != 0 ? ASSERT_LINE : CLEAR_LINE);
}
void ioc2_device::lower_local1_irq(uint8_t source_mask)
{
m_int3_local1_status_reg &= ~source_mask;
}
READ32_MEMBER( ioc2_device::read )
{
switch (offset)
{
case PI1_DATA_REG:
case PI1_CTRL_REG:
case PI1_STATUS_REG:
return m_pi1->read(space, offset, 0xff);
case PI1_DMA_CTRL_REG:
case PI1_INT_STATUS_REG:
case PI1_INT_MASK_REG:
case PI1_TIMER1_REG:
case PI1_TIMER2_REG:
case PI1_TIMER3_REG:
case PI1_TIMER4_REG:
return 0;
case SERIAL1_CMD_REG:
case SERIAL1_DATA_REG:
case SERIAL2_CMD_REG:
case SERIAL2_DATA_REG:
return m_scc->ba_cd_r(space, (offset - SERIAL1_CMD_REG) ^ 3);
case KBD_MOUSE_REGS1:
case KBD_MOUSE_REGS2:
return m_kbdc->data_r(space, (offset - KBD_MOUSE_REGS1) * 4);
case PANEL_REG:
return m_front_panel_reg;
case SYSID_REG:
return m_system_id;
case READ_REG:
return m_read_reg;
case DMA_SEL_REG:
// Bits 2-0 not quite understood, seem to be copy/paste error in SGI's own documents:
//
// 2 RW Parallel Port DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [this makes sense. -ed.]
// 1 RW ISDN Channel B DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [is this a copy/paste error? perhaps "Parallel Port" should be "ISDN Channel B"?]
// 0 RW [same text as above. Another copy/paste error, maybe? Should be channel A, with the bit selecting DMA channel 0/1 for ISDN channel A, the and the same for ISDN channel B in bit 1?]
return m_dma_sel;
case RESET_REG:
return m_reset_reg;
case WRITE_REG:
// Not yet implemented, some bits unnecessary:
//
// Bit Oper Description
// 7 RW Margin High. Set low for normal +5V operation, high to step supply up to +5.5V. Cleared at reset.
// 6 RW Margin Low. Set lowf or normal +5V operation, high to step supply down to +4.5V. Cleared at reset.
// 5 RW UART1 PC Mode. Set low to configure Port1 for RS422 Mac mode, high to select RS232 PC mode. Cleared at reset.
// 4 RW UART2 PC Mode. Set low to configure Port2 for RS422 Mac mode, high to select RS232 PC mode. Cleared at reset.
// 3 RW Ethernet Auto Select (active high). Set low for manual mode, high to have LXT901 automatically select TP or AUI based on link integrity. Cleared at reset.
// 2 RW Ethernet Port Select. Set low for TP, high for AUI. This setting is only used when Auto Select is in manual mode. Cleared at reset.
// 1 RW Ethernet UTP/STP select. Set low to select 150 ohm termination fro shielded TP (default), set high to select 100 ohm termination for unshielded TP. Cleared at reset.
// 0 RW Ethernet Normal Threshold (NTH) select. Set low to select the normal TP squelch threshold (default), high to reduce threshold by 4.5 dB (set low when reset).
return m_write_reg;
case INT3_LOCAL0_STATUS_REG:
return m_int3_local0_status_reg;
case INT3_LOCAL0_MASK_REG:
return m_int3_local0_mask_reg;
case INT3_LOCAL1_STATUS_REG:
return m_int3_local1_status_reg;
case INT3_LOCAL1_MASK_REG:
return m_int3_local1_mask_reg;
case INT3_MAP_STATUS_REG:
return m_int3_map_status_reg;
case INT3_MAP_MASK0_REG:
return m_int3_map_mask0_reg;
case INT3_MAP_MASK1_REG:
return m_int3_map_mask1_reg;
case INT3_MAP_POLARITY_REG:
return m_int3_map_pol_reg;
case INT3_TIMER_CLEAR_REG:
return m_int3_timer_clear_reg;
case INT3_ERROR_STATUS_REG:
return m_int3_err_status_reg;
case TIMER_COUNT0_REG:
case TIMER_COUNT1_REG:
case TIMER_COUNT2_REG:
case TIMER_CONTROL_REG:
return m_pit->read(space, offset - TIMER_COUNT0_REG);
}
return 0;
}
WRITE32_MEMBER( ioc2_device::write )
{
switch (offset)
{
case PI1_DATA_REG:
case PI1_CTRL_REG:
case PI1_STATUS_REG:
m_pi1->write(space, offset, data & 0xff, 0xff);
return;
case PI1_DMA_CTRL_REG:
case PI1_INT_STATUS_REG:
case PI1_INT_MASK_REG:
case PI1_TIMER1_REG:
case PI1_TIMER2_REG:
case PI1_TIMER3_REG:
case PI1_TIMER4_REG:
return;
case SERIAL1_CMD_REG:
case SERIAL1_DATA_REG:
case SERIAL2_CMD_REG:
case SERIAL2_DATA_REG:
m_scc->ba_cd_w(space, (offset - SERIAL1_CMD_REG) ^ 3, data & 0xff);
return;
case KBD_MOUSE_REGS1:
case KBD_MOUSE_REGS2:
m_kbdc->data_w(space, (offset - KBD_MOUSE_REGS1) * 4, data & 0xff);
return;
case PANEL_REG:
m_front_panel_reg &= ~(data & (FRONT_PANEL_VOL_UP_INT | FRONT_PANEL_VOL_DOWN_INT | FRONT_PANEL_POWER_BUTTON_INT));
return;
case DMA_SEL_REG:
{
// Bits 2-0 not quite understood, seem to be copy/paste error in SGI's own documents:
//
// 5:4 RW Serial Port Clock Select: 00 selects a 10MHz internal clock (default), 01 selects a 6.67MHz internal clock, and 02 or 03 selects the external clock input.
// 2 RW Parallel Port DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [this makes sense. -ed.]
// 1 RW ISDN Channel B DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [is this a copy/paste error? perhaps "Parallel Port" should be "ISDN Channel B"?]
// 0 RW [same text as above. Another copy/paste error, maybe? Should be channel A, with the bit selecting DMA channel 0/1 for ISDN channel A, the and the same for ISDN channel B in bit 1?]
uint8_t old = m_dma_sel;
m_dma_sel = data;
uint8_t diff = old ^ m_dma_sel;
if (diff & DMA_SEL_CLOCK_SEL_MASK)
{
if (diff & DMA_SEL_CLOCK_SEL_EXT)
{
logerror("%s: External clock select %sselected\n", machine().describe_context(), (old & DMA_SEL_CLOCK_SEL_EXT) != 0 ? "de" : "");
// TODO: verify the external Rx/Tx clock, is it fixed or programmable?
}
}
// TODO: Currently we always assume a 10MHz clock as PCLK
return;
}
case RESET_REG:
handle_reset_reg_write(data);
return;
case WRITE_REG:
m_write_reg = data;
return;
case INT3_LOCAL0_STATUS_REG:
case INT3_LOCAL1_STATUS_REG:
case INT3_MAP_STATUS_REG:
case INT3_ERROR_STATUS_REG:
// Read-only registers
return;
case INT3_LOCAL0_MASK_REG:
{
uint8_t old = m_int3_local0_mask_reg;
m_int3_local0_mask_reg = data;
bool old_line = (old & m_int3_local0_status_reg) != 0;
bool new_line = (m_int3_local0_mask_reg & m_int3_local0_status_reg) != 0;
if (old_line != new_line)
{
const uint32_t int_bits = (m_int3_local1_mask_reg & m_int3_local1_status_reg) | (m_int3_local0_mask_reg & m_int3_local0_status_reg);
m_maincpu->set_input_line(MIPS3_IRQ0, int_bits != 0 ? ASSERT_LINE : CLEAR_LINE);
}
return;
}
case INT3_LOCAL1_MASK_REG:
{
uint8_t old = m_int3_local1_mask_reg;
m_int3_local1_mask_reg = data;
bool old_line = (old & m_int3_local1_status_reg) != 0;
bool new_line = (m_int3_local1_mask_reg & m_int3_local1_status_reg) != 0;
if (old_line != new_line)
{
const uint32_t int_bits = (m_int3_local1_mask_reg & m_int3_local1_status_reg) | (m_int3_local0_mask_reg & m_int3_local0_status_reg);
m_maincpu->set_input_line(MIPS3_IRQ0, int_bits != 0 ? ASSERT_LINE : CLEAR_LINE);
}
return;
}
case INT3_MAP_MASK0_REG:
// TODO: Implement mappable interrupts
m_int3_map_mask0_reg = data;
return;
case INT3_MAP_MASK1_REG:
// TODO: Implement mappable interrupts
m_int3_map_mask1_reg = data;
return;
case INT3_MAP_POLARITY_REG:
// TODO: Mappable interrupt polarity select
m_int3_map_pol_reg = data;
return;
case TIMER_COUNT0_REG:
case TIMER_COUNT1_REG:
case TIMER_COUNT2_REG:
case TIMER_CONTROL_REG:
m_pit->write(space, offset - TIMER_COUNT0_REG, data & 0xff);
return;
}
}
void ioc2_device::handle_reset_reg_write(uint8_t data)
{
// guinness/fullhouse-specific implementations can handle bit 3 being used for ISDN reset on Indy only and bit 2 for EISA reset on Indigo 2 only, but for now we do nothing with it
m_reset_reg = data;
}
INPUT_CHANGED_MEMBER( ioc2_device::power_button )
{
if (!newval)
{
m_front_panel_reg |= FRONT_PANEL_POWER_BUTTON_INT;
}
}
INPUT_CHANGED_MEMBER( ioc2_device::volume_up )
{
if (!newval)
{
m_front_panel_reg |= FRONT_PANEL_VOL_UP_INT;
m_front_panel_reg |= FRONT_PANEL_VOL_UP_HOLD;
}
else
{
m_front_panel_reg &= ~FRONT_PANEL_VOL_UP_HOLD;
}
}
INPUT_CHANGED_MEMBER( ioc2_device::volume_down )
{
if (!newval)
{
m_front_panel_reg |= FRONT_PANEL_VOL_DOWN_INT;
m_front_panel_reg |= FRONT_PANEL_VOL_DOWN_HOLD;
}
else
{
m_front_panel_reg &= ~FRONT_PANEL_VOL_DOWN_HOLD;
}
}

215
src/mame/machine/ioc2.h Normal file
View File

@ -0,0 +1,215 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/**********************************************************************
SGI IOC2 I/O Controller emulation
**********************************************************************/
#ifndef MAME_MACHINE_IOC2_H
#define MAME_MACHINE_IOC2_H
#pragma once
#include "cpu/mips/mips3.h"
#include "machine/8042kbdc.h"
#include "machine/pc_lpt.h"
#include "machine/pckeybrd.h"
#include "machine/pit8253.h"
#include "machine/z80scc.h"
#define MCFG_IOC2_GUINNESS_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, SGI_IOC2_GUINNESS, 0)
#define MCFG_IOC2_FULL_HOUSE_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, SGI_IOC2_FULL_HOUSE, 0)
#define MCFG_IOC2_CPU(cpu_tag) \
downcast<ioc2_device &>(*device).set_cpu_tag(("^" cpu_tag));
class ioc2_device : public device_t
{
public:
void set_cpu_tag(const char *tag) { m_maincpu.set_tag(tag); }
DECLARE_WRITE32_MEMBER( write );
DECLARE_READ32_MEMBER( read );
DECLARE_INPUT_CHANGED_MEMBER( power_button );
DECLARE_INPUT_CHANGED_MEMBER( volume_down );
DECLARE_INPUT_CHANGED_MEMBER( volume_up );
void lower_local0_irq(uint8_t source_mask);
void raise_local0_irq(uint8_t source_mask);
void lower_local1_irq(uint8_t source_mask);
void raise_local1_irq(uint8_t source_mask);
enum
{
INT3_LOCAL0_FIFO = 0x01,
INT3_LOCAL0_SCSI0 = 0x02,
INT3_LOCAL0_SCSI1 = 0x04,
INT3_LOCAL0_ETHERNET = 0x08,
INT3_LOCAL0_MC_DMA = 0x10,
INT3_LOCAL0_PARALLEL = 0x20,
INT3_LOCAL0_GRAPHICS = 0x40,
INT3_LOCAL0_MAPPABLE0 = 0x80,
};
enum
{
INT3_LOCAL1_GP0 = 0x01,
INT3_LOCAL1_PANEL = 0x02,
INT3_LOCAL1_GP2 = 0x04,
INT3_LOCAL1_MAPPABLE1 = 0x08,
INT3_LOCAL1_HPC_DMA = 0x10,
INT3_LOCAL1_AC_FAIL = 0x20,
INT3_LOCAL1_VSYNC = 0x40,
INT3_LOCAL1_RETRACE = 0x80,
};
protected:
ioc2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t id);
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
enum
{
PI1_DATA_REG = 0x00/4,
PI1_CTRL_REG = 0x04/4,
PI1_STATUS_REG = 0x08/4,
PI1_DMA_CTRL_REG = 0x0c/4,
PI1_INT_STATUS_REG = 0x10/4,
PI1_INT_MASK_REG = 0x14/4,
PI1_TIMER1_REG = 0x18/4,
PI1_TIMER2_REG = 0x1c/4,
PI1_TIMER3_REG = 0x20/4,
PI1_TIMER4_REG = 0x24/4,
SERIAL1_CMD_REG = 0x30/4,
SERIAL1_DATA_REG = 0x34/4,
SERIAL2_CMD_REG = 0x38/4,
SERIAL2_DATA_REG = 0x3c/4,
KBD_MOUSE_REGS1 = 0x40/4,
KBD_MOUSE_REGS2 = 0x44/4,
GENCTRL_SELECT_REG = 0x48/4,
GENCTRL_REG = 0x4c/4,
PANEL_REG = 0x50/4,
SYSID_REG = 0x58/4,
READ_REG = 0x60/4,
DMA_SEL_REG = 0x68/4,
RESET_REG = 0x70/4,
WRITE_REG = 0x78/4,
INT3_LOCAL0_STATUS_REG = 0x80/4,
INT3_LOCAL0_MASK_REG = 0x84/4,
INT3_LOCAL1_STATUS_REG = 0x88/4,
INT3_LOCAL1_MASK_REG = 0x8c/4,
INT3_MAP_STATUS_REG = 0x90/4,
INT3_MAP_MASK0_REG = 0x94/4,
INT3_MAP_MASK1_REG = 0x98/4,
INT3_MAP_POLARITY_REG = 0x9c/4,
INT3_TIMER_CLEAR_REG = 0xa0/4,
INT3_ERROR_STATUS_REG = 0xa4/4,
TIMER_COUNT0_REG = 0xb0/4,
TIMER_COUNT1_REG = 0xb4/4,
TIMER_COUNT2_REG = 0xb8/4,
TIMER_CONTROL_REG = 0xbc/4,
};
enum
{
FRONT_PANEL_POWER_STATE = 0x01,
FRONT_PANEL_POWER_BUTTON_INT = 0x02,
FRONT_PANEL_VOL_DOWN_INT = 0x10,
FRONT_PANEL_VOL_DOWN_HOLD = 0x20,
FRONT_PANEL_VOL_UP_INT = 0x40,
FRONT_PANEL_VOL_UP_HOLD = 0x80,
};
enum
{
DMA_SEL_CLOCK_SEL_MASK = 0x30,
DMA_SEL_CLOCK_SEL_10MHz = 0x00,
DMA_SEL_CLOCK_SEL_6_67MHz = 0x10,
DMA_SEL_CLOCK_SEL_EXT = 0x20,
};
required_device<mips3_device> m_maincpu;
required_device<scc85230_device> m_scc;
required_device<pc_lpt_device> m_pi1; // we assume standard parallel port (SPP) mode
// TODO: SGI parallel port (SGIPP), HP BOISE high speed parallel port (HPBPP), and Ricoh scanner modes
required_device<kbdc8042_device> m_kbdc;
required_device<pit8254_device> m_pit;
virtual void handle_reset_reg_write(uint8_t data);
uint8_t m_gen_ctrl_select_reg;
uint8_t m_gen_ctrl_reg;
uint8_t m_front_panel_reg;
uint8_t m_read_reg;
uint8_t m_dma_sel;
uint8_t m_reset_reg;
uint8_t m_write_reg;
uint8_t m_int3_local0_status_reg;
uint8_t m_int3_local0_mask_reg;
uint8_t m_int3_local1_status_reg;
uint8_t m_int3_local1_mask_reg;
uint8_t m_int3_map_status_reg;
uint8_t m_int3_map_mask0_reg;
uint8_t m_int3_map_mask1_reg;
uint8_t m_int3_map_pol_reg;
uint8_t m_int3_timer_clear_reg;
uint8_t m_int3_err_status_reg;
uint32_t m_par_read_cnt;
uint32_t m_par_cntl;
uint8_t m_system_id;
static const char *SCC_TAG;
static const char *PI1_TAG;
static const char *KBDC_TAG;
static const char *PIT_TAG;
static const char *RS232A_TAG;
static const char *RS232B_TAG;
static const XTAL SCC_PCLK;
static const XTAL SCC_RXA_CLK;
static const XTAL SCC_TXA_CLK;
static const XTAL SCC_RXB_CLK;
static const XTAL SCC_TXB_CLK;
};
class ioc2_guinness_device : public ioc2_device
{
public:
ioc2_guinness_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
ioc2_guinness_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: ioc2_device(mconfig, type, tag, owner, clock, 0x01)
{ }
};
class ioc2_full_house_device : public ioc2_device
{
public:
ioc2_full_house_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
ioc2_full_house_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: ioc2_device(mconfig, type, tag, owner, clock, 0x20)
{ }
};
DECLARE_DEVICE_TYPE(SGI_IOC2_GUINNESS, ioc2_guinness_device)
DECLARE_DEVICE_TYPE(SGI_IOC2_FULL_HOUSE, ioc2_full_house_device)
#endif // MAME_MACHINE_IOC2_H