diff options
Diffstat (limited to 'src/devices/machine/i82586.cpp')
-rw-r--r-- | src/devices/machine/i82586.cpp | 357 |
1 files changed, 176 insertions, 181 deletions
diff --git a/src/devices/machine/i82586.cpp b/src/devices/machine/i82586.cpp index 83cc21ac53c..578d1a32979 100644 --- a/src/devices/machine/i82586.cpp +++ b/src/devices/machine/i82586.cpp @@ -31,9 +31,10 @@ #include "emu.h" #include "i82586.h" + #include "hashing.h" +#include "multibyte.h" -#define LOG_GENERAL (1U << 0) #define LOG_FRAMES (1U << 1) #define LOG_FILTER (1U << 2) #define LOG_CONFIG (1U << 3) @@ -96,7 +97,7 @@ CFG_PARAMS[] = { "number of retries", "maximum number of retries", 15, 7, 0xf0, 4, true }, { "no crc insertion", "crc appended to frame", 0, 8, 0x10, 4, false }, { "prefetch bit in rbd", "disabled (valid only in new modes)", 0, 0, 0x80, 7, false }, - { "preamble length", "bytes", 7, 3, 0x30, 4, true }, + { "preamble length", "2^(n+1) bytes", 2, 3, 0x30, 4, true }, { "preamble until crs", "disabled", 1, 11, 0x01, 0, false }, { "promiscuous mode", "address filter on", 0, 8, 0x01, 0, false }, { "padding", "no padding", 0, 8, 0x80, 7, false }, @@ -111,7 +112,7 @@ CFG_PARAMS[] = i82586_base_device::i82586_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endian, u8 datawidth, u8 addrwidth) : device_t(mconfig, type, tag, owner, clock) , device_memory_interface(mconfig, *this) - , device_network_interface(mconfig, *this, 10.0f) + , device_network_interface(mconfig, *this, 10) , m_space_config("shared", endian, datawidth, addrwidth) , m_out_irq(*this) , m_cx(false) @@ -120,6 +121,7 @@ i82586_base_device::i82586_base_device(const machine_config &mconfig, device_typ , m_rnr(false) , m_initialised(false) , m_reset(false) + , m_irq(false) , m_irq_assert(1) , m_cu_state(CU_IDLE) , m_ru_state(RU_IDLE) @@ -162,10 +164,7 @@ void i82586_base_device::device_start() { m_space = &space(0); - m_out_irq.resolve(); - - m_cu_timer = timer_alloc(CU_TIMER); - m_cu_timer->enable(false); + m_cu_timer = timer_alloc(FUNC(i82586_base_device::cu_execute), this); save_item(NAME(m_cx)); save_item(NAME(m_fr)); @@ -173,6 +172,7 @@ void i82586_base_device::device_start() save_item(NAME(m_rnr)); save_item(NAME(m_initialised)); save_item(NAME(m_reset)); + save_item(NAME(m_irq)); save_item(NAME(m_cu_state)); save_item(NAME(m_ru_state)); @@ -189,7 +189,7 @@ void i82586_base_device::device_start() void i82586_base_device::device_reset() { - m_cu_timer->enable(false); + m_cu_timer->reset(); m_cx = false; m_fr = false; @@ -201,16 +201,9 @@ void i82586_base_device::device_reset() m_ru_state = RU_IDLE; m_scp_address = SCP_ADDRESS; -} + m_mac_multi = 0; -void i82586_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - switch (id) - { - case CU_TIMER: - cu_execute(); - break; - } + set_irq(false); } device_memory_interface::space_config_vector i82586_base_device::memory_space_config() const @@ -220,7 +213,7 @@ device_memory_interface::space_config_vector i82586_base_device::memory_space_co }; } -WRITE_LINE_MEMBER(i82586_base_device::ca) +void i82586_base_device::ca(int state) { LOG("channel attention %s (%s)\n", state ? "asserted" : "cleared", machine().describe_context()); @@ -234,7 +227,7 @@ WRITE_LINE_MEMBER(i82586_base_device::ca) } } -WRITE_LINE_MEMBER(i82586_base_device::reset_w) +void i82586_base_device::reset_w(int state) { LOG("reset %s (%s)\n", state ? "asserted" : "cleared", machine().describe_context()); @@ -336,12 +329,12 @@ void i82586_base_device::process_scb() case CUC_RESUME: m_cu_state = CU_ACTIVE; - m_cu_timer->enable(true); + m_cu_timer->adjust(attotime::zero); break; case CUC_SUSPEND: m_cu_state = CU_SUSPENDED; - m_cu_timer->enable(false); + m_cu_timer->reset(); m_cna = true; break; @@ -406,7 +399,7 @@ void i82586_base_device::update_scb() set_irq(m_cx || m_fr || m_cna || m_rnr); } -void i82586_base_device::cu_execute() +TIMER_CALLBACK_MEMBER(i82586_base_device::cu_execute) { // fetch the command block command/status const u32 cb_cs = m_space->read_dword(m_cba); @@ -500,7 +493,7 @@ void i82586_base_device::cu_complete(const u16 status) if (cb_cs & CB_S) { m_cu_state = CU_SUSPENDED; - m_cu_timer->enable(false); + m_cu_timer->reset(); m_cna = true; } @@ -540,7 +533,7 @@ bool i82586_base_device::address_filter(u8 *mac) } // individual address - if (!memcmp(mac, get_mac(), cfg_address_length())) + if (!memcmp(mac, &get_mac()[0], cfg_address_length())) { LOGMASKED(LOG_FILTER, "address_filter accepted: individual address match\n"); @@ -566,9 +559,16 @@ void i82586_base_device::set_irq(bool irq) { LOG("irq asserted\n"); + // ensure an edge is generated if interrupt already asserted + if (m_irq) + m_out_irq(!m_irq_assert); + m_out_irq(m_irq_assert); - m_out_irq(!m_irq_assert); } + else if (m_irq) + m_out_irq(!m_irq_assert); + + m_irq = irq; } u32 i82586_base_device::compute_crc(u8 *buf, int length, bool crc16) @@ -582,7 +582,7 @@ u64 i82586_base_device::address_hash(u8 *buf, int length) // address hash is computed using bits 2-7 from crc of address u32 crc = compute_crc(buf, length, false); - return 1U << ((crc >> 2) & 0x3f); + return u64(1) << ((crc >> 2) & 0x3f); } int i82586_base_device::fetch_bytes(u8 *buf, u32 src, int length) @@ -821,7 +821,7 @@ void i82586_device::initialise() bool i82586_device::cu_iasetup() { int len = cfg_address_length(); - char mac[6]; + u8 mac[6]; u32 data; if (len != 6) @@ -832,14 +832,10 @@ bool i82586_device::cu_iasetup() } data = m_space->read_dword(m_cba + 4); - mac[0] = (data >> 16) & 0xff; - mac[1] = (data >> 24) & 0xff; + put_u16le(&mac[0], data >> 16); data = m_space->read_dword(m_cba + 8); - mac[2] = (data >> 0) & 0xff; - mac[3] = (data >> 8) & 0xff; - mac[4] = (data >> 16) & 0xff; - mac[5] = (data >> 24) & 0xff; + put_u32le(&mac[2], data); LOG("cu_iasetup individual address %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); set_mac(mac); @@ -893,35 +889,49 @@ bool i82586_device::cu_configure() bool i82586_device::cu_mcsetup() { - int addr_len = cfg_address_length(); - u16 mc_count; - u8 data[6]; + // read the address list length + int mc_count = m_space->read_word(m_cba + 6, TB_COUNT); + + // reset current list + m_mac_multi = 0; - if (addr_len != 6) + if (mc_count < cfg_address_length()) { - LOG("cu_mcsetup unexpected address length %d != 6\n", addr_len); - return false; - } + LOG("cu_mcsetup multicast filter disabled\n"); - // read the address count - mc_count = m_space->read_word(m_cba + 6, TB_COUNT); + return true; + } + else + LOG("cu_mcsetup configuring %d addresses\n", mc_count / cfg_address_length()); - // reset current list - LOG("mc_setup configuring %d addresses\n", mc_count); - m_mac_multi = 0; + std::vector<u8> buf; + offs_t offset = m_cba + 8; // read and process the addresses - for (int i = 0; i < mc_count; i++) + while (mc_count >= cfg_address_length()) { - *(u16 *)&data[0] = m_space->read_word(m_cba + 8 + i * 6 + 0); - *(u16 *)&data[1] = m_space->read_word(m_cba + 8 + i * 6 + 2); - *(u16 *)&data[2] = m_space->read_word(m_cba + 8 + i * 6 + 4); + // read an address + while (buf.size() < cfg_address_length()) + { + u16 const data = m_space->read_word(offset); + + buf.push_back(data >> 0); + buf.push_back(data >> 8); + + offset += 2; + } // add a hash of this address to the table - m_mac_multi |= address_hash(data, cfg_address_length()); + m_mac_multi |= address_hash(buf.data(), cfg_address_length()); - LOG("mc_setup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n", - data[0], data[1], data[2], data[3], data[4], data[5]); + if (cfg_address_length() == 6) + LOG("cu_mcsetup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + // remove used address bytes from the buffer + buf.erase(buf.begin(), buf.begin() + cfg_address_length()); + + mc_count -= cfg_address_length(); } return true; @@ -940,19 +950,17 @@ bool i82586_device::cu_transmit(u32 command) // optionally insert source, destination address and length (14 bytes) if (!cfg_no_src_add_ins()) { - const char *mac = get_mac(); + const std::array<u8, 6> &mac = get_mac(); u32 data; // insert destination address (6 bytes) data = m_space->read_dword(m_cba + 8); - buf[length++] = (data >> 0) & 0xff; - buf[length++] = (data >> 8) & 0xff; - buf[length++] = (data >> 16) & 0xff; - buf[length++] = (data >> 24) & 0xff; + put_u32le(&buf[length], data); + length += 4; data = m_space->read_dword(m_cba + 12); - buf[length++] = (data >> 0) & 0xff; - buf[length++] = (data >> 8) & 0xff; + put_u16le(&buf[length], data & 0xffff); + length += 2; // insert source address (6 bytes) LOG("cu_transmit inserting source address %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); @@ -961,8 +969,8 @@ bool i82586_device::cu_transmit(u32 command) // insert length (2 bytes) LOG("cu_transmit frame length 0x%04x\n", ((data >> 24) & 0xff) | ((data >> 16) & 0xff00)); - buf[length++] = (data >> 16) & 0xff; - buf[length++] = (data >> 24) & 0xff; + put_u16le(&buf[length], data >> 16); + length += 2; } // check if there is no tbd @@ -986,17 +994,15 @@ bool i82586_device::cu_transmit(u32 command) } // optionally compute/insert ethernet frame check sequence (4 bytes) - if (!cfg_no_crc_insertion() && !cfg_loopback_mode()) + if (!cfg_no_crc_insertion()) { LOG("cu_transmit inserting frame check sequence\n"); u32 crc = compute_crc(buf, length, cfg_crc16()); // insert the fcs - buf[length++] = (crc >> 0) & 0xff; - buf[length++] = (crc >> 8) & 0xff; - buf[length++] = (crc >> 16) & 0xff; - buf[length++] = (crc >> 24) & 0xff; + put_u32le(&buf[length], crc); + length += 4; } if (cfg_loopback_mode()) @@ -1016,7 +1022,7 @@ bool i82586_device::cu_transmit(u32 command) LOG("cu_transmit sending frame length %d\n", length); dump_bytes(buf, length); - return send(buf, length) == length; + return send(buf, length, 4) == length; } } @@ -1048,7 +1054,7 @@ bool i82586_device::cu_dump() memcpy(&buf[0x00], &m_cfg_bytes[0], CFG_SIZE); // individual address - memcpy(&buf[0x0c], get_mac(), 6); + memcpy(&buf[0x0c], &get_mac()[0], 6); // hash register *(u64 *)&buf[0x24] = m_mac_multi; @@ -1078,8 +1084,8 @@ u16 i82586_device::ru_execute(u8 *buf, int length) u32 rfd_cs = m_space->read_dword(m_rfd); u16 status = 0; - // current buffer position and bytes remaining - int position = 0, remaining = length; + // current buffer position and bytes remaining (excluding fcs) + int position = 0, remaining = length - 4; // set busy status m_space->write_dword(m_rfd, rfd_cs | RFD_B); @@ -1091,7 +1097,7 @@ u16 i82586_device::ru_execute(u8 *buf, int length) status |= RFD_S_SHORT; // set crc status - if (!cfg_loopback_mode() && ~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE) + if (~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE) { LOGMASKED(LOG_FRAMES, "ru_execute crc error computed 0x%08x stored 0x%08x\n", compute_crc(buf, length - 4, cfg_crc16()), *(u32 *)&buf[length - 4]); @@ -1173,18 +1179,18 @@ u16 i82586_device::ru_execute(u8 *buf, int length) void i82586_device::ru_complete(const u16 status) { - if (status & RFD_OK) - LOG("ru_complete frame received without error\n"); - else - LOG("ru_complete frame received with errors status 0x%04x\n", status); - - // update receive frame descriptor status - u32 rfd_cs = m_space->read_dword(m_rfd); - m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status); - // if we received without error, or we're saving bad frames, advance to the next rfd if ((status & RFD_OK) || cfg_save_bad_frames()) { + if (status & RFD_OK) + LOG("ru_complete frame received without error\n"); + else + LOG("ru_complete frame received with errors status 0x%04x\n", status); + + // update receive frame descriptor status + u32 rfd_cs = m_space->read_dword(m_rfd); + m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status); + if (!(rfd_cs & RFD_EL)) { // advance to next rfd @@ -1202,17 +1208,19 @@ void i82586_device::ru_complete(const u16 status) // set frame received status m_fr = true; - } - // suspend on completion - if (rfd_cs & RFD_S) - { - m_ru_state = RU_SUSPENDED; - m_rnr = true; - } + // suspend on completion + if (rfd_cs & RFD_S) + { + m_ru_state = RU_SUSPENDED; + m_rnr = true; + } - static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY" }; - LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]); + static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY" }; + LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]); + } + else + LOG("ru_complete discarded frame with errors status 0x%04x\n", status); } u32 i82586_device::address(u32 base, int offset, int address, u16 empty) @@ -1329,7 +1337,7 @@ bool i82596_device::cu_iasetup() { int len = cfg_address_length(); u32 data; - char mac[6]; + u8 mac[6]; if (len != 6) { @@ -1343,26 +1351,18 @@ bool i82596_device::cu_iasetup() case MODE_82586: case MODE_32SEGMENTED: data = m_space->read_dword(m_cba + 4); - mac[0] = (data >> 16) & 0xff; - mac[1] = (data >> 24) & 0xff; + put_u16le(&mac[0], data >> 16); data = m_space->read_dword(m_cba + 8); - mac[2] = (data >> 0) & 0xff; - mac[3] = (data >> 8) & 0xff; - mac[4] = (data >> 16) & 0xff; - mac[5] = (data >> 24) & 0xff; + put_u32le(&mac[2], data); break; case MODE_LINEAR: data = m_space->read_dword(m_cba + 8); - mac[0] = (data >> 0) & 0xff; - mac[1] = (data >> 8) & 0xff; - mac[2] = (data >> 16) & 0xff; - mac[3] = (data >> 24) & 0xff; + put_u32le(&mac[0], data); data = m_space->read_dword(m_cba + 12); - mac[4] = (data >> 0) & 0xff; - mac[5] = (data >> 8) & 0xff; + put_u16le(&mac[4], data & 0xffff); break; } @@ -1483,68 +1483,65 @@ bool i82596_device::cu_configure() bool i82596_device::cu_mcsetup() { - int addr_len = cfg_address_length(); - u16 mc_count = 0; - - int offset = 0; - u8 data[20]; - bool multi_ia; - - if (addr_len != 6) - { - LOG("cu_mcsetup unexpected address length %d != 6\n", addr_len); - return false; - } + u32 data = (mode() == MODE_LINEAR) ? m_space->read_dword(m_cba + 8) : m_space->read_word(m_cba + 6); + int mc_count = data & TB_COUNT; - switch (mode()) + // if length less than one address, clear multicast filter and finish + if (mc_count < cfg_address_length()) { - case MODE_82586: - case MODE_32SEGMENTED: - mc_count = m_space->read_word(m_cba + 6, TB_COUNT); - break; + LOG("cu_mcsetup multicast filter disabled\n"); + m_mac_multi = 0; - case MODE_LINEAR: - mc_count = m_space->read_word(m_cba + 8, TB_COUNT); - offset = 2; - break; + return true; } - // if count is zero, release multicast list and finish - if (mc_count == 0) + std::vector<u8> buf; + offs_t offset = m_cba + 8; + + // already have the first two address bytes in linear mode + if (mode() != MODE_LINEAR) { - LOG("mc_setup multicast filter disabled\n"); - m_mac_multi = 0; + data = m_space->read_dword(offset); - return true; + buf.push_back(data >> 0); + buf.push_back(data >> 8); } - - // fetch the first word - *(u32 *)&data[0] = m_space->read_dword(m_cba + 8); + buf.push_back(data >> 16); + buf.push_back(data >> 24); + offset += 4; // multi ia when configured and lsb of first address is clear - multi_ia = cfg_multi_ia() && !BIT(data[offset], 0); + bool const multi_ia = cfg_multi_ia() && !BIT(buf[0], 0); - // clear existing list - LOG("mc_setup configuring %d %s addresses\n", mc_count, multi_ia ? "multi-ia" : "multicast"); + LOG("cu_mcsetup configuring %d %s addresses\n", mc_count / cfg_address_length(), multi_ia ? "multi-ia" : "multicast"); (multi_ia ? m_mac_multi_ia : m_mac_multi) = 0; - for (int i = 0; i < mc_count; i++) + while (mc_count >= cfg_address_length()) { - // compute offset of address in 18 byte buffer - int n = (i % 3) * 6; + // read an address + while (buf.size() < cfg_address_length()) + { + data = m_space->read_dword(offset); - // read the next dword - *(u32 *)&data[n + 6] = m_space->read_dword(m_cba + 8 + i * 4 + 4); + buf.push_back(data >> 0); + buf.push_back(data >> 8); + buf.push_back(data >> 16); + buf.push_back(data >> 24); - // unaligned case needs special handling - if (n == 12 && offset == 2) - *(u16 *)&data[18] = *(u16 *)&data[0]; + offset += 4; + } // add a hash of this address to the table - (multi_ia ? m_mac_multi_ia : m_mac_multi) |= address_hash(&data[n + offset], cfg_address_length()); + (multi_ia ? m_mac_multi_ia : m_mac_multi) |= address_hash(buf.data(), cfg_address_length()); - LOG("mc_setup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n", - data[n + offset + 0], data[n + offset + 1], data[n + offset + 2], data[n + offset + 3], data[n + offset + 4], data[n + offset + 5]); + if (cfg_address_length() == 6) + LOG("cu_mcsetup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + // remove used address bytes from the buffer + buf.erase(buf.begin(), buf.begin() + cfg_address_length()); + + mc_count -= cfg_address_length(); } return true; @@ -1587,19 +1584,17 @@ bool i82596_device::cu_transmit(u32 command) // optionally insert destination, source and length (14 bytes) if (!cfg_no_src_add_ins()) { - const char *mac = get_mac(); + const std::array<u8, 6> &mac = get_mac(); u32 data; // insert destination address (6 bytes) data = m_space->read_dword(m_cba + 12 + offset); - buf[length++] = (data >> 0) & 0xff; - buf[length++] = (data >> 8) & 0xff; - buf[length++] = (data >> 16) & 0xff; - buf[length++] = (data >> 24) & 0xff; + put_u32le(&buf[length], data); + length += 4; data = m_space->read_dword(m_cba + 16 + offset); - buf[length++] = (data >> 0) & 0xff; - buf[length++] = (data >> 8) & 0xff; + put_u16le(&buf[length], data & 0xffff); + length += 2; // insert source address (6 bytes) LOG("cu_transmit inserting source address %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); @@ -1608,8 +1603,8 @@ bool i82596_device::cu_transmit(u32 command) // insert length from tcb (2 bytes) LOG("cu_transmit frame length 0x%04x\n", ((data >> 24) & 0xff) | ((data >> 16) & 0xff00)); - buf[length++] = (data >> 16) & 0xff; - buf[length++] = (data >> 24) & 0xff; + put_u16le(&buf[length], data >> 16); + length += 2; // insert payload from tcb LOG("cu_transmit inserting %d bytes from transmit command block\n", (tcb_count & TB_COUNT) - 8); @@ -1666,10 +1661,8 @@ bool i82596_device::cu_transmit(u32 command) u32 crc = compute_crc(buf, length, cfg_crc16()); // append the fcs - buf[length++] = (crc >> 0) & 0xff; - buf[length++] = (crc >> 8) & 0xff; - buf[length++] = (crc >> 16) & 0xff; - buf[length++] = (crc >> 24) & 0xff; + put_u32le(&buf[length], crc); + length += 4; } if (cfg_loopback_mode()) @@ -1726,7 +1719,7 @@ bool i82596_device::cu_dump() memcpy(&buf[0x02], &m_cfg_bytes[2], 9); // individual address - memcpy(&buf[0x0c], get_mac(), 6); + memcpy(&buf[0x0c], &get_mac()[0], 6); // hash register *(u64 *)&buf[0x24] = m_mac_multi; @@ -1737,7 +1730,7 @@ bool i82596_device::cu_dump() memcpy(&buf[0x00], &m_cfg_bytes[2], 12); // individual address - memcpy(&buf[0x0e], get_mac(), 6); + memcpy(&buf[0x0e], &get_mac()[0], 6); // hash register *(u64 *)&buf[0x26] = m_mac_multi; @@ -1816,7 +1809,7 @@ u16 i82596_device::ru_execute(u8 *buf, int length) } // set crc status - if (!cfg_loopback_mode() && ~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE) + if (~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE) { LOGMASKED(LOG_FRAMES, "ru_execute crc error computed 0x%08x stored 0x%08x\n", compute_crc(buf, length - 4, cfg_crc16()), *(u32 *)&buf[length - 4]); @@ -1834,7 +1827,7 @@ u16 i82596_device::ru_execute(u8 *buf, int length) // TODO: increment alignment error counter // set multicast status - if (mode() != MODE_82586 && memcmp(buf, get_mac(), cfg_address_length())) + if (mode() != MODE_82586 && memcmp(buf, &get_mac()[0], cfg_address_length())) status |= RFD_S_MULTICAST; // fetch initial rbd address from rfd @@ -1959,18 +1952,18 @@ u16 i82596_device::ru_execute(u8 *buf, int length) void i82596_device::ru_complete(const u16 status) { - if (status & RFD_OK) - LOG("ru_complete frame received without error\n"); - else - LOG("ru_complete frame received with errors status 0x%04x\n", status); - - // store status - const u32 rfd_cs = m_space->read_dword(m_rfd); - m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status); - // if we received without error, or we're saving bad frames, advance to the next rfd - if ((rfd_cs & RFD_OK) || cfg_save_bad_frames()) + if ((status & RFD_OK) || cfg_save_bad_frames()) { + if (status & RFD_OK) + LOG("ru_complete frame received without error\n"); + else + LOG("ru_complete frame received with errors status 0x%04x\n", status); + + // update receive frame descriptor status + const u32 rfd_cs = m_space->read_dword(m_rfd); + m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status); + if (!(rfd_cs & RFD_EL)) { // advance to next rfd @@ -1993,17 +1986,19 @@ void i82596_device::ru_complete(const u16 status) // set frame received status m_fr = true; - } - // suspend on completion - if (rfd_cs & RFD_S) - { - m_ru_state = RU_SUSPENDED; - m_rnr = true; - } + // suspend on completion + if (rfd_cs & RFD_S) + { + m_ru_state = RU_SUSPENDED; + m_rnr = true; + } - static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY", nullptr, nullptr, nullptr, nullptr, nullptr, "NO RESOURCES (RFD)", nullptr, "NO RESOURCES (RBD)" }; - LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]); + static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY", nullptr, nullptr, nullptr, nullptr, nullptr, "NO RESOURCES (RFD)", nullptr, "NO RESOURCES (RBD)" }; + LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]); + } + else + LOG("ru_complete discarded frame with errors status 0x%04x\n", status); } u32 i82596_device::address(u32 base, int offset, int address, u16 empty) |