summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2021-01-07 18:28:35 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2021-01-07 18:28:35 +0700
commitded9173f789302e68c0f08de591d3f55ff9008bc (patch)
tree172711bb680de7ced456feae749c3fe52bc8a8dc /src
parente74bcd7752a82fbd6cbe1fe2f72837b00d093d68 (diff)
i82586: fix address hash and multicast setup bugs
Diffstat (limited to 'src')
-rw-r--r--src/devices/machine/i82586.cpp137
1 files changed, 74 insertions, 63 deletions
diff --git a/src/devices/machine/i82586.cpp b/src/devices/machine/i82586.cpp
index 83cc21ac53c..7dfc6272435 100644
--- a/src/devices/machine/i82586.cpp
+++ b/src/devices/machine/i82586.cpp
@@ -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)
@@ -893,35 +893,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);
- if (addr_len != 6)
+ // reset current list
+ m_mac_multi = 0;
+
+ 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());
+
+ 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]);
- LOG("mc_setup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n",
- data[0], data[1], data[2], data[3], data[4], data[5]);
+ // remove used address bytes from the buffer
+ buf.erase(buf.begin(), buf.begin() + cfg_address_length());
+
+ mc_count -= cfg_address_length();
}
return true;
@@ -1483,68 +1497,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;
+ 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;
- if (addr_len != 6)
+ // if length less than one address, clear multicast filter and finish
+ if (mc_count < cfg_address_length())
{
- LOG("cu_mcsetup unexpected address length %d != 6\n", addr_len);
- return false;
- }
-
- switch (mode())
- {
- 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());
+
+ 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());
- 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]);
+ mc_count -= cfg_address_length();
}
return true;