dp83932c: fix receive overflow logic

This commit is contained in:
Patrick Mackinlay 2024-01-18 15:53:55 +07:00
parent dc9384250f
commit e94c4e37e9

View File

@ -112,11 +112,19 @@ void dp83932c_device::device_reset()
int dp83932c_device::recv_start_cb(u8 *buf, int length)
{
unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
if (!(m_reg[CR] & CR_RXEN))
// check for receiver disabled or overflow condition
if (!(m_reg[CR] & CR_RXEN) || (m_reg[ISR] & (ISR_RDE | ISR_RBE)))
return -1;
// reload receive descriptor address after end of list encountered
if (BIT(m_reg[CRDA], 0))
{
m_reg[CRDA] = read_bus_word(EA(m_reg[URDA], m_reg[LLFA]));
if (BIT(m_reg[CRDA], 0))
return -2;
}
m_reg[RCR] &= ~(RCR_MC | RCR_BC | RCR_LPKT | RCR_CRCR | RCR_FAER | RCR_LBK | RCR_PRX);
// address filter
@ -137,25 +145,12 @@ int dp83932c_device::recv_start_cb(u8 *buf, int length)
else
m_reg[RCR] |= RCR_PRX;
LOG("recv_start_cb %d\n", length);
// loopback
if (m_reg[RCR] & RCR_LB)
m_reg[RCR] |= RCR_LBK;
dump_bytes(buf, length);
if (m_reg[CRDA] & 1)
{
// re-read the previous descriptor link field
m_reg[CRDA] = read_bus_word(EA(m_reg[URDA], m_reg[LLFA]));
if (m_reg[CRDA] & 1)
{
logerror("no receive descriptor available\n");
return -2;
}
}
// save rba pointer registers
m_reg[TRBA0] = m_reg[CRBA0];
m_reg[TRBA1] = m_reg[CRBA1];
@ -172,6 +167,7 @@ int dp83932c_device::recv_start_cb(u8 *buf, int length)
// update remaining buffer word count
u32 const rbwc = ((u32(m_reg[RBWC1]) << 16) | m_reg[RBWC0]) - (length + 1) / 2;
LOG("recv_start_cb length %d buffer %d remaining %d\n", length, ((u32(m_reg[RBWC1]) << 16) | m_reg[RBWC0]) * 2, rbwc * 2);
m_reg[RBWC1] = rbwc >> 16;
m_reg[RBWC0] = u16(rbwc);
@ -180,6 +176,7 @@ int dp83932c_device::recv_start_cb(u8 *buf, int length)
// write status to rda
// TODO: don't write the rda if rba limit exceeded (buffer overflow)
unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
offs_t const rda = EA(m_reg[URDA], m_reg[CRDA]);
write_bus_word(rda + 0 * width, m_reg[RCR]);
write_bus_word(rda + 1 * width, length);
@ -190,8 +187,11 @@ int dp83932c_device::recv_start_cb(u8 *buf, int length)
m_reg[CRDA] = read_bus_word(rda + 5 * width);
// check for end of list
if (m_reg[CRDA] & 1)
if (BIT(m_reg[CRDA], 0))
{
LOG("recv_start_cb end of list\n");
m_reg[ISR] |= ISR_RDE;
}
else
write_bus_word(rda + 6 * width, 0);
@ -209,6 +209,7 @@ void dp83932c_device::recv_complete_cb(int result)
if (result > 0)
{
m_reg[ISR] |= ISR_PKTRX;
update_interrupts();
}
}
@ -268,8 +269,11 @@ void dp83932c_device::reg_w(offs_t offset, u16 data)
break;
case ISR:
// reload rra when rbe is cleared
if ((m_reg[offset] & ISR_RBE) && (data & ISR_RBE))
read_rra();
m_reg[offset] &= ~(data & regmask[offset]);
// TODO: reload rra after RBE cleared
update_interrupts();
break;
@ -359,6 +363,8 @@ void dp83932c_device::transmit()
m_reg[TPS] = read_bus_word(tda + word++ * width);
m_reg[TFC] = read_bus_word(tda + word++ * width);
LOG("transmit tda 0x%08x tps %d tfc %d\n", tda, m_reg[TPS], m_reg[TFC]);
// check for programmable interrupt
if ((m_reg[TCR] & TCR_PINT) && !(tcr & TCR_PINT))
m_reg[ISR] |= ISR_PINT;
@ -376,6 +382,7 @@ void dp83932c_device::transmit()
m_reg[TFS] = read_bus_word(tda + word++ * width);
offs_t const tsa = EA(m_reg[TSA1], m_reg[TSA0]);
LOG("transmit tsa 0x%08x tfs %d\n", tsa, m_reg[TFS]);
// FIXME: word/dword transfers (allow unaligned)
for (unsigned byte = 0; byte < m_reg[TFS]; byte++)
@ -395,6 +402,8 @@ void dp83932c_device::transmit()
// advance ctda to the link field
m_reg[CTDA] += word * width;
LOG("transmit length %d word %d tda 0x%08x\n", length, word, EA(m_reg[UTDA], m_reg[CTDA]));
// transmit data
dump_bytes(buf, length);
send(buf, length, 4);
@ -420,7 +429,7 @@ void dp83932c_device::send_complete_cb(int result)
m_reg[CTDA] = read_bus_word(EA(m_reg[UTDA], m_reg[CTDA]));
// check for end of list
if (m_reg[CTDA] & 1)
if (BIT(m_reg[CTDA], 0))
{
m_reg[ISR] |= ISR_TXDN;
m_reg[CR] &= ~CR_TXP;