smc91c9x: Set link to be unconnected by default to keep warfa (vegas) from hanging. (nw)

This commit is contained in:
Ted Green 2017-05-16 18:58:03 -06:00
parent 6b44b4d3c4
commit c62e5bc8ca
3 changed files with 55 additions and 7 deletions

View File

@ -108,6 +108,7 @@ static const char *const ethernet_regname[64] =
smc91c9x_device::smc91c9x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, m_irq_handler(*this)
, m_link_unconnected(true)
{
}
@ -118,6 +119,8 @@ smc91c9x_device::smc91c9x_device(const machine_config &mconfig, device_type type
void smc91c9x_device::device_start()
{
m_irq_handler.resolve_safe();
// TX timer
m_tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(smc91c9x_device::finish_enqueue), this));
/* register ide states */
save_item(NAME(m_reg));
@ -178,6 +181,7 @@ void smc91c9x_device::device_reset()
m_reg[EREG_ERCV] = 0x331f; m_regmask[EREG_ERCV] = 0x009f;
update_ethernet_irq();
m_tx_timer->adjust(attotime::never);
}
@ -211,8 +215,9 @@ void smc91c9x_device::update_ethernet_irq()
/* update the IRQ state */
m_irq_state = ((mask & state) != 0);
if (!m_irq_handler.isnull())
if (!m_irq_handler.isnull()) {
m_irq_handler(m_irq_state ? ASSERT_LINE : CLEAR_LINE);
}
}
@ -231,7 +236,7 @@ void smc91c9x_device::update_stats()
finish_enqueue - complete an enqueued packet
-------------------------------------------------*/
void smc91c9x_device::finish_enqueue(int param)
TIMER_CALLBACK_MEMBER(smc91c9x_device::finish_enqueue)
{
int is_broadcast = (m_tx[4] == 0xff && m_tx[5] == 0xff && m_tx[6] == 0xff &&
m_tx[7] == 0xff && m_tx[8] == 0xff && m_tx[9] == 0xff);
@ -251,7 +256,7 @@ void smc91c9x_device::finish_enqueue(int param)
update_stats();
/* loopback? */
if (m_reg[EREG_TCR] & 0x2002)
if (m_reg[EREG_TCR] & 0x2002) {
if (m_fifo_count < ETHER_RX_BUFFERS)
{
int buffer_len = ((m_tx[3] << 8) | m_tx[2]) & 0x7ff;
@ -280,9 +285,9 @@ void smc91c9x_device::finish_enqueue(int param)
if (m_reg[EREG_TCR & 0x0080])
if (packet_len < 64)
{
memset(&packet[buffer_len], 0, 64+6 - buffer_len);
memset(&packet[buffer_len], 0, 64 + 6 - buffer_len);
packet[buffer_len - 1] = 0;
buffer_len = 64+6;
buffer_len = 64 + 6;
packet[2] = buffer_len;
packet[3] = buffer_len >> 8;
}
@ -291,6 +296,25 @@ void smc91c9x_device::finish_enqueue(int param)
m_reg[EREG_INTERRUPT] |= EINT_RCV;
m_reg[EREG_FIFO_PORTS] &= ~0x8000;
}
}
else if (m_link_unconnected) {
// Set lost carrier
if (m_reg[EREG_TCR] & 0x0400) {
m_reg[EREG_EPH_STATUS] |= 0x400;
// Clear Tx Enable on error
m_reg[EREG_TCR] &= ~0x1;
}
// Set signal quality error
if (m_reg[EREG_TCR] & 0x1000) {
m_reg[EREG_EPH_STATUS] |= 0x20;
// Clear Tx Enable on error
m_reg[EREG_TCR] &= ~0x1;
}
// signal a no transmit
m_reg[EREG_INTERRUPT] &= ~EINT_TX;
// Set a ethernet phy status interrupt
m_reg[EREG_INTERRUPT] |= EINT_EPH;
}
update_ethernet_irq();
}
@ -354,7 +378,8 @@ void smc91c9x_device::process_command(uint16_t data)
case ECMD_ENQUEUE_PACKET:
if (LOG_ETHERNET)
logerror(" ENQUEUE TX PACKET\n");
finish_enqueue(0);
// Set some delay before tranmit ends
m_tx_timer->adjust(attotime::from_usec(100));
break;
case ECMD_RESET_FIFOS:
@ -440,6 +465,12 @@ WRITE16_MEMBER( smc91c9x_device::write )
switch (offset)
{
case EREG_TCR: /* transmit control register */
// Setting Tx Enable clears some status and interrupts
if (data & 0x1) {
m_reg[EREG_EPH_STATUS] &= ~0x420;
m_reg[EREG_INTERRUPT] &= ~EINT_EPH;
update_ethernet_irq();
}
if (LOG_ETHERNET)
{
if (data & 0x2000) logerror(" EPH LOOP\n");

View File

@ -37,6 +37,9 @@ private:
// internal state
devcb_write_line m_irq_handler;
// link unconnected
bool m_link_unconnected;
/* raw register data and masks */
uint16_t m_reg[64];
uint16_t m_regmask[64];
@ -58,8 +61,10 @@ private:
void update_ethernet_irq();
void update_stats();
void finish_enqueue(int param);
TIMER_CALLBACK_MEMBER(finish_enqueue);
void process_command(uint16_t data);
emu_timer* m_tx_timer;
};

View File

@ -602,6 +602,8 @@ WRITE8_MEMBER(vegas_state::sio_w)
int index = offset >> 12;
switch (index) {
case 0:
if (LOG_SIO)
logerror("sio_w: Reset Control offset: %08x index: %d data: %02X\n", offset, index, data);
// Reset Control: Bit 0=>Reset IOASIC, Bit 1=>Reset NSS Connection, Bit 2=>Reset SMC, Bit 3=>Reset VSYNC, Bit 4=>VSYNC Polarity
m_sio_irq_clear = data;
@ -621,6 +623,14 @@ WRITE8_MEMBER(vegas_state::sio_w)
break;
case 1:
// Interrupt Enable
// Bit 0 => SIO Watchdog
// Bit 1 => A/D Converter
// Bit 2 => IOASIC
// Bit 3 => NSS / Hi-Link
// Bit 4 => Ethernet
// Bit 5 => Vsync
if (LOG_SIO)
logerror("sio_w: Interrupt Enable offset: %08x index: %d data: %02X\n", offset, index, data);
m_sio_irq_enable = data;
update_sio_irqs();
break;
@ -1247,6 +1257,7 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START(vegas_cs3_map, AS_PROGRAM, 32, vegas_state)
AM_RANGE(0x00000000, 0x00000003) AM_READWRITE(analog_port_r, analog_port_w)
//AM_RANGE(0x00001000, 0x00001003) AM_READWRITE(lcd_r, lcd_w)
ADDRESS_MAP_END
static ADDRESS_MAP_START(vegas_cs4_map, AS_PROGRAM, 32, vegas_state)
@ -1267,6 +1278,7 @@ static ADDRESS_MAP_START(vegas_cs6_map, AS_PROGRAM, 32, vegas_state)
ADDRESS_MAP_END
static ADDRESS_MAP_START(vegas_cs7_map, AS_PROGRAM, 32, vegas_state)
//AM_RANGE(0x00000000, 0x00000003) AM_READWRITE8(nss_r, nss_w, 0xffffffff)
AM_RANGE(0x00001000, 0x0000100f) AM_READWRITE(ethernet_r, ethernet_w)
AM_RANGE(0x00005000, 0x00005003) AM_DEVWRITE("dcs", dcs_audio_device, dsio_idma_addr_w) // if (m_dcs_idma_cs == 7)
AM_RANGE(0x00007000, 0x00007003) AM_DEVREADWRITE("dcs", dcs_audio_device, dsio_idma_data_r, dsio_idma_data_w) // if (m_dcs_idma_cs == 7)