From c62e5bc8ca5c7764a107c9fc9e1f8853b8ebadb2 Mon Sep 17 00:00:00 2001 From: Ted Green Date: Tue, 16 May 2017 18:58:03 -0600 Subject: [PATCH] smc91c9x: Set link to be unconnected by default to keep warfa (vegas) from hanging. (nw) --- src/devices/machine/smc91c9x.cpp | 43 +++++++++++++++++++++++++++----- src/devices/machine/smc91c9x.h | 7 +++++- src/mame/drivers/vegas.cpp | 12 +++++++++ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/devices/machine/smc91c9x.cpp b/src/devices/machine/smc91c9x.cpp index 4905581af21..201c8c6fc22 100644 --- a/src/devices/machine/smc91c9x.cpp +++ b/src/devices/machine/smc91c9x.cpp @@ -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"); diff --git a/src/devices/machine/smc91c9x.h b/src/devices/machine/smc91c9x.h index 3723049a639..78627fb58d3 100644 --- a/src/devices/machine/smc91c9x.h +++ b/src/devices/machine/smc91c9x.h @@ -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; + }; diff --git a/src/mame/drivers/vegas.cpp b/src/mame/drivers/vegas.cpp index 3020a8ac8fa..a504e2908c7 100644 --- a/src/mame/drivers/vegas.cpp +++ b/src/mame/drivers/vegas.cpp @@ -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)