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) 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) : device_t(mconfig, type, tag, owner, clock)
, m_irq_handler(*this) , 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() void smc91c9x_device::device_start()
{ {
m_irq_handler.resolve_safe(); 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 */ /* register ide states */
save_item(NAME(m_reg)); save_item(NAME(m_reg));
@ -178,6 +181,7 @@ void smc91c9x_device::device_reset()
m_reg[EREG_ERCV] = 0x331f; m_regmask[EREG_ERCV] = 0x009f; m_reg[EREG_ERCV] = 0x331f; m_regmask[EREG_ERCV] = 0x009f;
update_ethernet_irq(); update_ethernet_irq();
m_tx_timer->adjust(attotime::never);
} }
@ -211,9 +215,10 @@ void smc91c9x_device::update_ethernet_irq()
/* update the IRQ state */ /* update the IRQ state */
m_irq_state = ((mask & state) != 0); 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); 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 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 && 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); 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(); update_stats();
/* loopback? */ /* loopback? */
if (m_reg[EREG_TCR] & 0x2002) if (m_reg[EREG_TCR] & 0x2002) {
if (m_fifo_count < ETHER_RX_BUFFERS) if (m_fifo_count < ETHER_RX_BUFFERS)
{ {
int buffer_len = ((m_tx[3] << 8) | m_tx[2]) & 0x7ff; int buffer_len = ((m_tx[3] << 8) | m_tx[2]) & 0x7ff;
@ -291,6 +296,25 @@ void smc91c9x_device::finish_enqueue(int param)
m_reg[EREG_INTERRUPT] |= EINT_RCV; m_reg[EREG_INTERRUPT] |= EINT_RCV;
m_reg[EREG_FIFO_PORTS] &= ~0x8000; 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(); update_ethernet_irq();
} }
@ -354,7 +378,8 @@ void smc91c9x_device::process_command(uint16_t data)
case ECMD_ENQUEUE_PACKET: case ECMD_ENQUEUE_PACKET:
if (LOG_ETHERNET) if (LOG_ETHERNET)
logerror(" ENQUEUE TX PACKET\n"); logerror(" ENQUEUE TX PACKET\n");
finish_enqueue(0); // Set some delay before tranmit ends
m_tx_timer->adjust(attotime::from_usec(100));
break; break;
case ECMD_RESET_FIFOS: case ECMD_RESET_FIFOS:
@ -440,6 +465,12 @@ WRITE16_MEMBER( smc91c9x_device::write )
switch (offset) switch (offset)
{ {
case EREG_TCR: /* transmit control register */ 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 (LOG_ETHERNET)
{ {
if (data & 0x2000) logerror(" EPH LOOP\n"); if (data & 0x2000) logerror(" EPH LOOP\n");

View File

@ -37,6 +37,9 @@ private:
// internal state // internal state
devcb_write_line m_irq_handler; devcb_write_line m_irq_handler;
// link unconnected
bool m_link_unconnected;
/* raw register data and masks */ /* raw register data and masks */
uint16_t m_reg[64]; uint16_t m_reg[64];
uint16_t m_regmask[64]; uint16_t m_regmask[64];
@ -58,8 +61,10 @@ private:
void update_ethernet_irq(); void update_ethernet_irq();
void update_stats(); void update_stats();
void finish_enqueue(int param); TIMER_CALLBACK_MEMBER(finish_enqueue);
void process_command(uint16_t data); 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; int index = offset >> 12;
switch (index) { switch (index) {
case 0: 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 // 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; m_sio_irq_clear = data;
@ -621,6 +623,14 @@ WRITE8_MEMBER(vegas_state::sio_w)
break; break;
case 1: case 1:
// Interrupt Enable // 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; m_sio_irq_enable = data;
update_sio_irqs(); update_sio_irqs();
break; break;
@ -1247,6 +1257,7 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START(vegas_cs3_map, AS_PROGRAM, 32, vegas_state) 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(0x00000000, 0x00000003) AM_READWRITE(analog_port_r, analog_port_w)
//AM_RANGE(0x00001000, 0x00001003) AM_READWRITE(lcd_r, lcd_w)
ADDRESS_MAP_END ADDRESS_MAP_END
static ADDRESS_MAP_START(vegas_cs4_map, AS_PROGRAM, 32, vegas_state) 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 ADDRESS_MAP_END
static ADDRESS_MAP_START(vegas_cs7_map, AS_PROGRAM, 32, vegas_state) 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(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(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) AM_RANGE(0x00007000, 0x00007003) AM_DEVREADWRITE("dcs", dcs_audio_device, dsio_idma_data_r, dsio_idma_data_w) // if (m_dcs_idma_cs == 7)