diff options
Diffstat (limited to 'src/devices/machine/dp83932c.cpp')
-rw-r--r-- | src/devices/machine/dp83932c.cpp | 159 |
1 files changed, 92 insertions, 67 deletions
diff --git a/src/devices/machine/dp83932c.cpp b/src/devices/machine/dp83932c.cpp index 092b3949ac2..3d35d80a9dd 100644 --- a/src/devices/machine/dp83932c.cpp +++ b/src/devices/machine/dp83932c.cpp @@ -22,9 +22,10 @@ #include "emu.h" #include "dp83932c.h" + #include "hashing.h" +#include "multibyte.h" -#define LOG_GENERAL (1U << 0) #define LOG_COMMAND (1U << 1) #define LOG_FILTER (1U << 2) #define LOG_PACKETS (1U << 3) @@ -66,7 +67,7 @@ static u16 const regmask[] = dp83932c_device::dp83932c_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : device_t(mconfig, DP83932C, tag, owner, clock) - , device_network_interface(mconfig, *this, 10.0f) + , device_network_interface(mconfig, *this, 10) , m_bus(*this, finder_base::DUMMY_TAG, 0) , m_out_int(*this) , m_int_state(false) @@ -80,9 +81,7 @@ void dp83932c_device::map(address_map &map) void dp83932c_device::device_start() { - m_out_int.resolve(); - - m_command = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp83932c_device::command), this)); + m_command = timer_alloc(FUNC(dp83932c_device::command), this); save_item(NAME(m_int_state)); save_item(NAME(m_reg)); @@ -113,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 @@ -138,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] = m_bus->read_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]; @@ -173,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); @@ -181,20 +176,24 @@ 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]); - m_bus->write_word(rda + 0 * width, m_reg[RCR]); - m_bus->write_word(rda + 1 * width, length); - m_bus->write_word(rda + 2 * width, m_reg[CRBA0]); - m_bus->write_word(rda + 3 * width, m_reg[CRBA1]); - m_bus->write_word(rda + 4 * width, m_reg[RSC]); + write_bus_word(rda + 0 * width, m_reg[RCR]); + write_bus_word(rda + 1 * width, length); + write_bus_word(rda + 2 * width, m_reg[CRBA0]); + write_bus_word(rda + 3 * width, m_reg[CRBA1]); + write_bus_word(rda + 4 * width, m_reg[RSC]); m_reg[LLFA] = m_reg[CRDA] + 5 * width; - m_reg[CRDA] = m_bus->read_word(rda + 5 * width); + 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 - m_bus->write_word(rda + 6 * width, 0); + write_bus_word(rda + 6 * width, 0); // handle buffer exhaustion if (rbwc < m_reg[EOBC]) @@ -210,6 +209,7 @@ void dp83932c_device::recv_complete_cb(int result) if (result > 0) { m_reg[ISR] |= ISR_PKTRX; + update_interrupts(); } } @@ -231,11 +231,8 @@ void dp83932c_device::reg_w(offs_t offset, u16 data) m_reg[CR] &= ~CR_RST; } - - return; } - - if (data & CR_RST) + else if (data & CR_RST) { LOGMASKED(LOG_COMMAND, "enter software reset\n"); @@ -243,12 +240,22 @@ void dp83932c_device::reg_w(offs_t offset, u16 data) m_reg[CR] &= ~(CR_LCAM | CR_RRRA | CR_TXP | CR_HTX); m_reg[CR] |= (CR_RST | CR_RXDIS); - - return; } - - m_reg[offset] |= data & regmask[offset]; - m_command->adjust(attotime::zero, data & regmask[offset]); + else + { + u16 cmd_to_run = data & regmask[offset]; + if (m_reg[CR] & CR_TXP) + { + // Per section 3.5.4 in the datasheet, TDAs can be dynamically added. + // The TXP command will be re-sent by the host, but doesn't do anything + // unless the SONIC finished the last commmand right before the TDA was + // appended to the list. So, null the CR_TXP bit if it was already set + // so we don't smash the currently running transmission. + cmd_to_run &= ~CR_TXP; + } + m_reg[offset] |= data & regmask[offset]; + m_command->adjust(attotime::zero, cmd_to_run); + } break; case RCR: @@ -262,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; @@ -284,7 +294,7 @@ void dp83932c_device::reg_w(offs_t offset, u16 data) } } -void dp83932c_device::command(void *ptr, s32 param) +void dp83932c_device::command(s32 param) { if (param & CR_HTX) { @@ -349,9 +359,11 @@ void dp83932c_device::transmit() // read control information from tda and load registers u16 const tcr = m_reg[TCR]; - m_reg[TCR] = m_bus->read_word(tda + word++ * width) & TCR_TPC; - m_reg[TPS] = m_bus->read_word(tda + word++ * width); - m_reg[TFC] = m_bus->read_word(tda + word++ * width); + m_reg[TCR] = read_bus_word(tda + word++ * width) & TCR_TPC; + 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)) @@ -365,11 +377,12 @@ void dp83932c_device::transmit() for (unsigned fragment = 0; fragment < m_reg[TFC]; fragment++) { // read fragment address and size - m_reg[TSA0] = m_bus->read_word(tda + word++ * width); - m_reg[TSA1] = m_bus->read_word(tda + word++ * width); - m_reg[TFS] = m_bus->read_word(tda + word++ * width); + m_reg[TSA0] = read_bus_word(tda + word++ * width); + m_reg[TSA1] = read_bus_word(tda + word++ * width); + 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++) @@ -382,15 +395,15 @@ void dp83932c_device::transmit() u32 const crc = util::crc32_creator::simple(buf, length); // insert the fcs - buf[length++] = crc >> 0; - buf[length++] = crc >> 8; - buf[length++] = crc >> 16; - buf[length++] = crc >> 24; + put_u32le(&buf[length], crc); + length += 4; } // 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); @@ -407,16 +420,16 @@ void dp83932c_device::send_complete_cb(int result) } // write descriptor status - m_bus->write_word(EA(m_reg[UTDA], m_reg[TTDA]), m_reg[TCR] & TCR_TPS); + write_bus_word(EA(m_reg[UTDA], m_reg[TTDA]), m_reg[TCR] & TCR_TPS); // check for halt if (!(m_reg[CR] & CR_HTX)) { // load next descriptor address - m_reg[CTDA] = m_bus->read_word(EA(m_reg[UTDA], m_reg[CTDA])); + 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; @@ -440,10 +453,10 @@ void dp83932c_device::read_rra(bool command) offs_t const rrp = EA(m_reg[URRA], m_reg[RRP]); - m_reg[CRBA0] = m_bus->read_word(rrp + 0 * width); - m_reg[CRBA1] = m_bus->read_word(rrp + 1 * width); - m_reg[RBWC0] = m_bus->read_word(rrp + 2 * width); - m_reg[RBWC1] = m_bus->read_word(rrp + 3 * width); + m_reg[CRBA0] = read_bus_word(rrp + 0 * width); + m_reg[CRBA1] = read_bus_word(rrp + 1 * width); + m_reg[RBWC0] = read_bus_word(rrp + 2 * width); + m_reg[RBWC1] = read_bus_word(rrp + 3 * width); LOG("read_rra crba 0x%08x rbwc 0x%08x\n", EA(m_reg[CRBA1], m_reg[CRBA0]), EA(m_reg[RBWC1], m_reg[RBWC0])); @@ -472,10 +485,10 @@ void dp83932c_device::load_cam() { offs_t const cdp = EA(m_reg[URRA], m_reg[CDP]); - u16 const cep = m_bus->read_word(cdp + 0 * width) & 0xf; - u16 const cap0 = m_bus->read_word(cdp + 1 * width); - u16 const cap1 = m_bus->read_word(cdp + 2 * width); - u16 const cap2 = m_bus->read_word(cdp + 3 * width); + u16 const cep = read_bus_word(cdp + 0 * width) & 0xf; + u16 const cap0 = read_bus_word(cdp + 1 * width); + u16 const cap1 = read_bus_word(cdp + 2 * width); + u16 const cap2 = read_bus_word(cdp + 3 * width); // FIXME: documented byte/word order doesn't match emulation @@ -483,15 +496,16 @@ void dp83932c_device::load_cam() cep, u8(cap0), cap0 >> 8, u8(cap1), cap1 >> 8, u8(cap2), cap2 >> 8); m_cam[cep] = - (u64(u8(cap0 >> 0)) << 40) | (u64(u8(cap0 >> 8)) << 32) | (u64(u8(cap1 >> 0)) << 24) | - (u64(u8(cap1 >> 8)) << 16) | (u64(u8(cap2 >> 0)) << 8) | (u64(u8(cap2 >> 8)) << 0); + (u64(swapendian_int16(cap0)) << 32) | + (u64(swapendian_int16(cap1)) << 16) | + (u64(swapendian_int16(cap2)) << 0); m_reg[CDP] += 4 * width; m_reg[CDC]--; } // read cam enable - m_reg[CE] = m_bus->read_word(EA(m_reg[URRA], m_reg[CDP])); + m_reg[CE] = read_bus_word(EA(m_reg[URRA], m_reg[CDP])); LOG("load_cam enable 0x%04x\n", m_reg[CE]); m_reg[CR] &= ~CR_LCAM; @@ -518,9 +532,7 @@ bool dp83932c_device::address_filter(u8 *buf) return true; } - u64 const address = - (u64(buf[0]) << 40) | (u64(buf[1]) << 32) | (u64(buf[2]) << 24) | - (u64(buf[3]) << 16) | (u64(buf[4]) << 8) | (u64(buf[5]) << 0); + u64 const address = get_u48be(buf); // broadcast if ((address == 0xffff'ffffffffULL) && (m_reg[RCR] & (RCR_AMC | RCR_BRD))) @@ -572,3 +584,16 @@ void dp83932c_device::dump_bytes(u8 *buf, int length) buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]); } } + +u16 dp83932c_device::read_bus_word(offs_t address) +{ + return (m_reg[DCR] & DCR_DW) ? m_bus->read_dword(address) : m_bus->read_word(address); +} + +void dp83932c_device::write_bus_word(offs_t address, u16 data) +{ + if (m_reg[DCR] & DCR_DW) + m_bus->write_dword(address, data); + else + m_bus->write_word(address, data); +} |