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:
parent
7c932d2b5c
commit
3349e3e990
@ -1,13 +1,43 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Ryan Holtz
|
// copyright-holders:Patrick Mackinlay
|
||||||
/*****************************************************************************
|
|
||||||
|
|
||||||
AMD Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)
|
/*
|
||||||
|
* AMD Am7990 Local Area Network Controller for Ethernet (LANCE) and Am79C90
|
||||||
TODO:
|
* CMOS Local Area Network Controller for Ethernet (C-LANCE).
|
||||||
- Error handling
|
*
|
||||||
|
* 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 "emu.h"
|
||||||
#include "am79c90.h"
|
#include "am79c90.h"
|
||||||
@ -89,8 +119,6 @@ void am7990_device_base::device_reset()
|
|||||||
m_csr[3] = 0;
|
m_csr[3] = 0;
|
||||||
m_lb_length = 0;
|
m_lb_length = 0;
|
||||||
|
|
||||||
m_transmit_poll->enable(false);
|
|
||||||
|
|
||||||
update_interrupts();
|
update_interrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +131,7 @@ void am7990_device_base::update_interrupts()
|
|||||||
{
|
{
|
||||||
m_intr_out_state = !m_intr_out_state;
|
m_intr_out_state = !m_intr_out_state;
|
||||||
m_intr_out_cb(m_intr_out_state);
|
m_intr_out_cb(m_intr_out_state);
|
||||||
|
LOG("interrupt asserted\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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];
|
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]);
|
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
|
// write the data to memory
|
||||||
int const count = std::min(length - offset, rx_buf_length);
|
int const count = std::min(length - offset, rx_buf_length);
|
||||||
dma_out(rx_buf_address, &buf[offset], count);
|
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);
|
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)
|
void am7990_device_base::transmit_poll(void *ptr, s32 param)
|
||||||
{
|
{
|
||||||
// receive pending internal loopback data
|
// 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);
|
int const result = receive(m_lb_buf, m_lb_length);
|
||||||
m_lb_length = 0;
|
m_lb_length = 0;
|
||||||
@ -259,12 +290,17 @@ void am7990_device_base::transmit_poll(void *ptr, s32 param)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 const ring_address = (m_tx_ring_base + (m_tx_ring_pos << 3)) & RING_ADDR_MASK;
|
if (m_csr[0] & CSR0_TXON)
|
||||||
m_tx_md[1] = m_dma_in_cb(ring_address | 2);
|
{
|
||||||
|
m_csr[0] &= ~CSR0_TDMD;
|
||||||
|
|
||||||
// start transmitting if we own the current descriptor
|
u32 const ring_address = (m_tx_ring_base + (m_tx_ring_pos << 3)) & RING_ADDR_MASK;
|
||||||
if (m_tx_md[1] & TMD1_OWN)
|
m_tx_md[1] = m_dma_in_cb(ring_address | 2);
|
||||||
transmit();
|
|
||||||
|
// start transmitting if we own the current descriptor
|
||||||
|
if (m_tx_md[1] & TMD1_OWN)
|
||||||
|
transmit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void am7990_device_base::transmit()
|
void am7990_device_base::transmit()
|
||||||
@ -293,7 +329,7 @@ void am7990_device_base::transmit()
|
|||||||
m_transmit_poll->enable(false);
|
m_transmit_poll->enable(false);
|
||||||
|
|
||||||
// check whether to append fcs or not
|
// 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];
|
u8 buf[4096];
|
||||||
int length = 0;
|
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];
|
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]);
|
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)
|
// 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)))
|
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);
|
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
|
// turn off the transmitter
|
||||||
m_csr[0] &= ~CSR0_TXON;
|
m_csr[0] &= ~CSR0_TXON;
|
||||||
m_transmit_poll->enable(false);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,7 +389,7 @@ void am7990_device_base::transmit()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compute and append the fcs
|
// compute and append the fcs
|
||||||
if (add_fcs)
|
if (append_fcs)
|
||||||
{
|
{
|
||||||
u32 const crc = util::crc32_creator::simple(buf, length);
|
u32 const crc = util::crc32_creator::simple(buf, length);
|
||||||
|
|
||||||
@ -380,7 +417,7 @@ void am7990_device_base::transmit()
|
|||||||
return;
|
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)
|
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;
|
m_csr[0] |= CSR0_TINT | CSR0_INTR;
|
||||||
update_interrupts();
|
update_interrupts();
|
||||||
|
|
||||||
// TODO: back-to-back transmit
|
// resume transmit polling (back-to-back)
|
||||||
|
m_transmit_poll->adjust(attotime::zero, 0, TX_POLL_PERIOD);
|
||||||
// resume transmit polling
|
|
||||||
m_transmit_poll->enable(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
READ16_MEMBER(am7990_device_base::regs_r)
|
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());
|
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
|
else
|
||||||
return m_rap;
|
return m_rap;
|
||||||
@ -528,14 +566,14 @@ WRITE16_MEMBER(am7990_device_base::regs_w)
|
|||||||
m_csr[0] &= ~CSR0_TXON;
|
m_csr[0] &= ~CSR0_TXON;
|
||||||
else
|
else
|
||||||
m_csr[0] |= CSR0_TXON;
|
m_csr[0] |= CSR0_TXON;
|
||||||
|
|
||||||
if (m_csr[0] & CSR0_TXON)
|
|
||||||
m_transmit_poll->enable(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// transmit demand
|
// 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);
|
m_transmit_poll->adjust(attotime::zero, 0, TX_POLL_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
// ERR == BABL || CERR || MISS || MERR
|
// ERR == BABL || CERR || MISS || MERR
|
||||||
if (m_csr[0] & CSR0_ANY_ERR)
|
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
|
// Datasheet says "must be zero", but doesn't indicate what
|
||||||
// happens if it's written non-zero. Must be writable to pass
|
// happens if it's written non-zero. Must be writable to pass
|
||||||
// system diagnostic on MIPS RS2030.
|
// system diagnostic on MIPS RS2030.
|
||||||
m_csr[1] = data;
|
if (m_csr[0] & CSR0_STOP)
|
||||||
|
m_csr[1] = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // Most significant 8 bits of the Initialization Block
|
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".
|
// write as zero, while LANCE datasheet just says "reserved".
|
||||||
// MIPS RS2030 diagnostic requires these bits to be writable,
|
// MIPS RS2030 diagnostic requires these bits to be writable,
|
||||||
// so assuming this is older device behaviour.
|
// 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;
|
break;
|
||||||
|
|
||||||
case 3: // Bus master interface
|
case 3: // Bus master interface
|
||||||
m_csr[3] = data & CSR3_MASK;
|
if (m_csr[0] & CSR0_STOP)
|
||||||
|
m_csr[3] = data & CSR3_MASK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -588,10 +629,7 @@ void am7990_device_base::initialize()
|
|||||||
LOG("INITIALIZE initialization block address 0x%08x\n", init_addr);
|
LOG("INITIALIZE initialization block address 0x%08x\n", init_addr);
|
||||||
|
|
||||||
for (int i = 0; i < 12; i++)
|
for (int i = 0; i < 12; i++)
|
||||||
{
|
|
||||||
init_block[i] = m_dma_in_cb(init_addr + i * 2);
|
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];
|
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_IDON | CSR0_INIT;
|
||||||
m_csr[0] &= ~CSR0_STOP;
|
m_csr[0] &= ~CSR0_STOP;
|
||||||
|
|
||||||
m_transmit_poll->enable(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void am7990_device_base::dma_in(u32 address, u8 *buf, int length)
|
void am7990_device_base::dma_in(u32 address, u8 *buf, int length)
|
||||||
|
@ -1,40 +1,5 @@
|
|||||||
// license:BSD-3-Clause
|
// 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
|
|
||||||
|
|
||||||
******************************************************************************
|
|
||||||
_____ _____
|
|
||||||
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
|
|
||||||
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#ifndef MAME_MACHINE_AM79C90_H
|
#ifndef MAME_MACHINE_AM79C90_H
|
||||||
#define MAME_MACHINE_AM79C90_H
|
#define MAME_MACHINE_AM79C90_H
|
||||||
|
Loading…
Reference in New Issue
Block a user