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
This commit is contained in:
Patrick Mackinlay 2018-11-22 14:46:45 +07:00
parent 7c932d2b5c
commit 3349e3e990
2 changed files with 75 additions and 74 deletions

View File

@ -1,13 +1,43 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/*****************************************************************************
// copyright-holders:Patrick Mackinlay
AMD Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)
TODO:
- Error handling
*****************************************************************************/
/*
* 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)

View File

@ -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