summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2018-11-22 14:46:45 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2018-11-22 14:46:45 +0700
commit3349e3e990ab54cf46cea19180ce36f91bd0281d (patch)
treeb7378a9d5929ad10d092c8b229db0f5917f4f93e
parent7c932d2b5c86d4ac69f949490be7d347548d5938 (diff)
am79c90: fixes (nw)
* took over copyright due to near-total rewrite * tweaked logging * corrected tx/rx on/off behaviour * block register access while not stopped * crc error is an error
-rw-r--r--src/devices/machine/am79c90.cpp114
-rw-r--r--src/devices/machine/am79c90.h37
2 files changed, 76 insertions, 75 deletions
diff --git a/src/devices/machine/am79c90.cpp b/src/devices/machine/am79c90.cpp
index 4ea0fd2ba7f..ab447a13d8a 100644
--- a/src/devices/machine/am79c90.cpp
+++ b/src/devices/machine/am79c90.cpp
@@ -1,13 +1,43 @@
// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/*****************************************************************************
-
- AMD Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)
-
- TODO:
- - Error handling
-
-*****************************************************************************/
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * AMD Am7990 Local Area Network Controller for Ethernet (LANCE) and Am79C90
+ * CMOS Local Area Network Controller for Ethernet (C-LANCE).
+ *
+ * Sources:
+ *
+ * https://datasheet.datasheetarchive.com/originals/distributors/Datasheets-115/DSAP00824.pdf
+ *
+ * TODO
+ * - hp9k/3xx diagnostic failures
+ *
+ * _____ _____
+ * Vss 1 |* \_/ | 48 Vdd
+ * DAL7 2 | | 47 DAL8
+ * DAL6 3 | | 46 DAL9
+ * DAL5 4 | | 45 DAL10
+ * DAL4 5 | | 44 DAL11
+ * DAL3 6 | | 43 DAL12
+ * DAL2 7 | | 42 DAL13
+ * DAL1 8 | | 41 DAL14
+ * DAL0 9 | | 40 DAL15
+ * READ 10 | | 39 A16
+ * /INTR 11 | | 38 A17
+ * /DALI 12 | Am79C90 | 37 A18
+ * /DALI 13 | | 36 A19
+ * /DAS 14 | | 35 A20
+ * /BM0,BYTE 15 | | 34 A21
+ * /BM1,/BUSAKO 16 | | 33 A22
+ * /HOLD,/BUSRQ 17 | | 32 A23
+ * ALE,/AS 18 | | 31 RX
+ * /HLDA 19 | | 30 RENA
+ * /CS 20 | | 29 TX
+ * ADR 21 | | 28 CLSN
+ * /READY 22 | | 27 RCLK
+ * /RESET 23 | | 26 TENA
+ * Vss 24 |_____________| 25 TCLK
+ */
#include "emu.h"
#include "am79c90.h"
@@ -89,8 +119,6 @@ void am7990_device_base::device_reset()
m_csr[3] = 0;
m_lb_length = 0;
- m_transmit_poll->enable(false);
-
update_interrupts();
}
@@ -103,6 +131,7 @@ void am7990_device_base::update_interrupts()
{
m_intr_out_state = !m_intr_out_state;
m_intr_out_cb(m_intr_out_state);
+ LOG("interrupt asserted\n");
}
}
else
@@ -171,6 +200,8 @@ int am7990_device_base::receive(u8 *buf, int length)
u32 const rx_buf_address = (u32(m_rx_md[1] & 0xff) << 16) | m_rx_md[0];
int const rx_buf_length = -s16(m_rx_md[2]);
+ LOGMASKED(LOG_RXTX, "receive buffer address 0x%06x length %d\n", rx_buf_address, rx_buf_length);
+
// write the data to memory
int const count = std::min(length - offset, rx_buf_length);
dma_out(rx_buf_address, &buf[offset], count);
@@ -213,7 +244,7 @@ int am7990_device_base::receive(u8 *buf, int length)
{
LOGMASKED(LOG_RXTX, "receive incorrect fcs 0x%08x\n", ~crc);
- m_rx_md[1] |= RMD1_CRC;
+ m_rx_md[1] |= RMD1_ERR | RMD1_CRC;
}
}
@@ -250,7 +281,7 @@ void am7990_device_base::recv_complete_cb(int result)
void am7990_device_base::transmit_poll(void *ptr, s32 param)
{
// receive pending internal loopback data
- if (m_lb_length && (m_mode & MODE_LOOP) && (m_mode & MODE_INTL))
+ if (m_lb_length && (m_mode & MODE_LOOP) && (m_mode & MODE_INTL) && (m_csr[0] & CSR0_RXON))
{
int const result = receive(m_lb_buf, m_lb_length);
m_lb_length = 0;
@@ -259,12 +290,17 @@ void am7990_device_base::transmit_poll(void *ptr, s32 param)
return;
}
- u32 const ring_address = (m_tx_ring_base + (m_tx_ring_pos << 3)) & RING_ADDR_MASK;
- m_tx_md[1] = m_dma_in_cb(ring_address | 2);
+ if (m_csr[0] & CSR0_TXON)
+ {
+ m_csr[0] &= ~CSR0_TDMD;
- // start transmitting if we own the current descriptor
- if (m_tx_md[1] & TMD1_OWN)
- transmit();
+ u32 const ring_address = (m_tx_ring_base + (m_tx_ring_pos << 3)) & RING_ADDR_MASK;
+ m_tx_md[1] = m_dma_in_cb(ring_address | 2);
+
+ // start transmitting if we own the current descriptor
+ if (m_tx_md[1] & TMD1_OWN)
+ transmit();
+ }
}
void am7990_device_base::transmit()
@@ -293,7 +329,7 @@ void am7990_device_base::transmit()
m_transmit_poll->enable(false);
// check whether to append fcs or not
- bool const add_fcs = !(m_mode & MODE_DTCR) || ((type() == AM79C90) && (m_tx_md[1] & TMD1_ADD_FCS));
+ bool const append_fcs = !(m_mode & MODE_DTCR) || ((type() == AM79C90) && (m_tx_md[1] & TMD1_ADD_FCS));
u8 buf[4096];
int length = 0;
@@ -308,6 +344,8 @@ void am7990_device_base::transmit()
u32 const tx_buf_address = (u32(m_tx_md[1] & 0xff) << 16) | m_tx_md[0];
u16 const tx_buf_length = -s16(m_tx_md[2]);
+ LOGMASKED(LOG_RXTX, "transmit buffer address 0x%06x length %d\n", tx_buf_address, tx_buf_length);
+
// minimum length 100 when chaining, or 64 when not (except for internal loopback mode)
if (!length && tx_buf_length < ((m_tx_md[1] & TMD1_ENP) ? 64 : 100) && ((m_mode & (MODE_LOOP | MODE_INTL)) != (MODE_LOOP | MODE_INTL)))
logerror("first transmit buffer length %d less than required minimum\n", tx_buf_length);
@@ -343,7 +381,6 @@ void am7990_device_base::transmit()
// turn off the transmitter
m_csr[0] &= ~CSR0_TXON;
- m_transmit_poll->enable(false);
break;
}
}
@@ -352,7 +389,7 @@ void am7990_device_base::transmit()
}
// compute and append the fcs
- if (add_fcs)
+ if (append_fcs)
{
u32 const crc = util::crc32_creator::simple(buf, length);
@@ -380,7 +417,7 @@ void am7990_device_base::transmit()
return;
}
- int const fcs_length = add_fcs ? 4 : 0;
+ int const fcs_length = append_fcs ? 4 : 0;
if ((length - fcs_length) < 8 || (length - fcs_length) > 32)
{
@@ -432,10 +469,8 @@ void am7990_device_base::send_complete_cb(int result)
m_csr[0] |= CSR0_TINT | CSR0_INTR;
update_interrupts();
- // TODO: back-to-back transmit
-
- // resume transmit polling
- m_transmit_poll->enable(true);
+ // resume transmit polling (back-to-back)
+ m_transmit_poll->adjust(attotime::zero, 0, TX_POLL_PERIOD);
}
READ16_MEMBER(am7990_device_base::regs_r)
@@ -444,7 +479,10 @@ READ16_MEMBER(am7990_device_base::regs_r)
{
LOGMASKED(LOG_REG, "regs_r csr%d data 0x%04x (%s)\n", m_rap, m_csr[m_rap], machine().describe_context());
- return m_csr[m_rap];
+ if (m_rap && !(m_csr[0] & CSR0_STOP))
+ return space.unmap();
+ else
+ return m_csr[m_rap];
}
else
return m_rap;
@@ -528,14 +566,14 @@ WRITE16_MEMBER(am7990_device_base::regs_w)
m_csr[0] &= ~CSR0_TXON;
else
m_csr[0] |= CSR0_TXON;
-
- if (m_csr[0] & CSR0_TXON)
- m_transmit_poll->enable(true);
}
// transmit demand
- if ((data & CSR0_TDMD) && (m_csr[0] & CSR0_TXON))
+ if ((data & CSR0_TDMD) && !(m_csr[0] & CSR0_TDMD))
+ {
+ m_csr[0] |= CSR0_TDMD;
m_transmit_poll->adjust(attotime::zero, 0, TX_POLL_PERIOD);
+ }
// ERR == BABL || CERR || MISS || MERR
if (m_csr[0] & CSR0_ANY_ERR)
@@ -560,7 +598,8 @@ WRITE16_MEMBER(am7990_device_base::regs_w)
// Datasheet says "must be zero", but doesn't indicate what
// happens if it's written non-zero. Must be writable to pass
// system diagnostic on MIPS RS2030.
- m_csr[1] = data;
+ if (m_csr[0] & CSR0_STOP)
+ m_csr[1] = data;
break;
case 2: // Most significant 8 bits of the Initialization Block
@@ -568,11 +607,13 @@ WRITE16_MEMBER(am7990_device_base::regs_w)
// write as zero, while LANCE datasheet just says "reserved".
// MIPS RS2030 diagnostic requires these bits to be writable,
// so assuming this is older device behaviour.
- m_csr[2] = (type() == AM7990) ? data : (data & 0x00ff);
+ if (m_csr[0] & CSR0_STOP)
+ m_csr[2] = (type() == AM7990) ? data : (data & 0x00ff);
break;
case 3: // Bus master interface
- m_csr[3] = data & CSR3_MASK;
+ if (m_csr[0] & CSR0_STOP)
+ m_csr[3] = data & CSR3_MASK;
break;
}
}
@@ -588,10 +629,7 @@ void am7990_device_base::initialize()
LOG("INITIALIZE initialization block address 0x%08x\n", init_addr);
for (int i = 0; i < 12; i++)
- {
init_block[i] = m_dma_in_cb(init_addr + i * 2);
- LOGMASKED(LOG_INIT, "IADR +%02d: 0x%04x\n", i * 2, init_block[i]);
- }
m_mode = init_block[0];
@@ -623,8 +661,6 @@ void am7990_device_base::initialize()
m_csr[0] |= CSR0_IDON | CSR0_INIT;
m_csr[0] &= ~CSR0_STOP;
-
- m_transmit_poll->enable(false);
}
void am7990_device_base::dma_in(u32 address, u8 *buf, int length)
diff --git a/src/devices/machine/am79c90.h b/src/devices/machine/am79c90.h
index ac2e17ee336..0597dbdb944 100644
--- a/src/devices/machine/am79c90.h
+++ b/src/devices/machine/am79c90.h
@@ -1,40 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/*****************************************************************************
-
- AMD Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)
-
- TODO:
- - Error handling
-
-******************************************************************************
- _____ _____
- Vss 1 |* \_/ | 48 Vdd
- DAL7 2 | | 47 DAL8
- DAL6 3 | | 46 DAL9
- DAL5 4 | | 45 DAL10
- DAL4 5 | | 44 DAL11
- DAL3 6 | | 43 DAL12
- DAL2 7 | | 42 DAL13
- DAL1 8 | | 41 DAL14
- DAL0 9 | | 40 DAL15
- READ 10 | | 39 A16
- /INTR 11 | | 38 A17
- /DALI 12 | Am79C90 | 37 A18
- /DALI 13 | | 36 A19
- /DAS 14 | | 35 A20
- /BM0,BYTE 15 | | 34 A21
- /BM1,/BUSAKO 16 | | 33 A22
- /HOLD,/BUSRQ 17 | | 32 A23
- ALE,/AS 18 | | 31 RX
- /HLDA 19 | | 30 RENA
- /CS 20 | | 29 TX
- ADR 21 | | 28 CLSN
- /READY 22 | | 27 RCLK
- /RESET 23 | | 26 TENA
- Vss 24 |_____________| 25 TCLK
-
-**********************************************************************/
+// copyright-holders:Patrick Mackinlay
#ifndef MAME_MACHINE_AM79C90_H
#define MAME_MACHINE_AM79C90_H