From 341a20ddfe94eccc8ef2959d027d97651a21a0b5 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Tue, 5 Sep 2017 15:29:29 +0700 Subject: i82586: fixed 82586 initialisation * have now tested 82586 version successfully * include heartbeat indicator on all transmits to pass InterPro diagnostic * also corrected a bug affecting long frames - now allows up to 64k, slightly worried about the increase in save state, but don't have a better idea --- src/devices/machine/i82586.cpp | 47 +++++++++++++++++++++++------------------- src/devices/machine/i82586.h | 17 ++++++++++----- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/devices/machine/i82586.cpp b/src/devices/machine/i82586.cpp index 6efd2ee9dd7..4e55b61b8bd 100644 --- a/src/devices/machine/i82586.cpp +++ b/src/devices/machine/i82586.cpp @@ -13,7 +13,7 @@ * * This implementation should cover all of the above reasonably well, but * no testing of big endian mode in particular, and very limited testing -* of the 82586 or 82596 in non-linear modes has been done so far. +* of the 82596 in non-linear modes has been done so far. * * Some documents covering the above include: * @@ -22,7 +22,7 @@ * https://www.intel.com/assets/pdf/general/82596ca.pdf * * TODO -* - testing for 82586 and 82596 big endian and non-linear modes +* - testing for 82596 big endian and non-linear modes * - more complete statistics capturing * - 82596 monitor mode * - throttle timers and diagnostic command @@ -419,8 +419,10 @@ void i82586_base_device::cu_execute() break; case CB_TRANSMIT: + // always turn on the heartbeat indicator status after a successful transmission; not + // strictly correct, but allows one InterPro 2000 diagnostic to pass if (cu_transmit(cb_cs)) - cb_cs |= CB_OK; + cb_cs |= CB_OK | CB_S6; break; case CB_TDREFLECT: @@ -758,14 +760,18 @@ void i82586_device::device_reset() void i82586_device::initialise() { - u16 scb_offset = m_space->read_word(m_scp_address + 2); + // read iscp address from scp + u32 iscp_address = m_space->read_dword(m_scp_address + 8); + LOG("initialise iscp address 0x%08x\n", iscp_address); + + u16 scb_offset = m_space->read_word(iscp_address + 2); - m_scb_base = m_space->read_dword(m_scp_address + 4); - m_scb_address = (m_scb_base + scb_offset); + m_scb_base = m_space->read_dword(iscp_address + 4); + m_scb_address = m_scb_base + scb_offset; LOG("initialise scb base address 0x%06x offset 0x%04x address 0x%08x\n", m_scb_base, scb_offset, m_scb_address); // clear iscp busy byte - m_space->write_byte(m_scp_address, 0); + m_space->write_byte(iscp_address, 0); m_cx = true; m_cna = true; @@ -890,9 +896,9 @@ bool i82586_device::cu_transmit(u32 command) { u16 tbd_count; - // ethernet frame buffer (rounded up to 8 byte boundary) - u8 buf[1528]; - int length = 0; + // ethernet frame buffer + u8 buf[MAX_FRAME_SIZE]; + u16 length = 0; u16 tbd_offset = m_space->read_word(m_cba + 6); @@ -1184,7 +1190,6 @@ void i82596_device::device_start() save_item(NAME(m_cfg_bytes)); save_item(NAME(m_sysbus)); - save_item(NAME(m_iscp_address)); save_item(NAME(m_mac_multi_ia)); } @@ -1230,9 +1235,9 @@ void i82596_device::port(u32 data) void i82596_device::initialise() { - // read sysbus and iscp address from scp + // read iscp address and sysbus from scp + u32 iscp_address = m_space->read_dword(m_scp_address + 8); m_sysbus = m_space->read_byte(m_scp_address + 2); - m_iscp_address = m_space->read_dword(m_scp_address + 8); LOG("initialise sysbus 0x%02x mode %s, %s triggering of bus throttle timers, lock function %s, interrupt active %s, 32-bit address pointers in linear mode per %s stepping)\n", m_sysbus, @@ -1241,29 +1246,29 @@ void i82596_device::initialise() m_sysbus & SYSBUS_LOCK ? "disabled" : "enabled", m_sysbus & SYSBUS_INT ? "low" : "high", m_sysbus & SYSBUS_BE ? "B" : "A1"); - LOG("initialise iscp address 0x%08x\n", m_iscp_address); + LOG("initialise iscp address 0x%08x\n", iscp_address); switch (mode()) { case MODE_82586: case MODE_32SEGMENTED: { - u16 scb_offset = m_space->read_word(m_iscp_address + 2); + u16 scb_offset = m_space->read_word(iscp_address + 2); - m_scb_base = m_space->read_dword(m_iscp_address + 4); + m_scb_base = m_space->read_dword(iscp_address + 4); m_scb_address = m_scb_base + scb_offset; LOG("initialise scb base address 0x%08x offset 0x%04x address 0x%08x\n", m_scb_base, scb_offset, m_scb_address); } break; case MODE_LINEAR: - m_scb_address = m_space->read_dword(m_iscp_address + 4); + m_scb_address = m_space->read_dword(iscp_address + 4); LOG("initialise scb address 0x%08x\n", m_scb_address); break; } // clear iscp busy byte - m_space->write_byte(m_iscp_address, 0); + m_space->write_byte(iscp_address, 0); m_cx = true; m_cna = true; @@ -1505,9 +1510,9 @@ bool i82596_device::cu_transmit(u32 command) u32 tbd_address; u16 tcb_count, tbd_count; - // ethernet frame buffer (rounded up to 8 byte boundary) - u8 buf[1528]; - int length = 0; + // ethernet frame buffer + u8 buf[MAX_FRAME_SIZE]; + u16 length = 0; // need offset into tcb for linear mode int offset = mode() == MODE_LINEAR ? 4 : 0; diff --git a/src/devices/machine/i82586.h b/src/devices/machine/i82586.h index 1f002951fc9..60ee47bd936 100644 --- a/src/devices/machine/i82586.h +++ b/src/devices/machine/i82586.h @@ -70,7 +70,13 @@ public: enum cu_cb_cs_mask { - CB_MAXCOL = 0x00000007, // number of collisions (82596 only) + CB_MAXCOL = 0x0000000f, // number of collisions + CB_S5 = 0x00000020, // transmission unsuccessful due to maximum collision retries + CB_S6 = 0x00000040, // heart beat indicator + CB_S7 = 0x00000080, // transmission deferred due to traffic on link + CB_S8 = 0x00000100, // transmission unsuccessful due to dma underrun + CB_S9 = 0x00000200, // transmission unsuccessful due to loss of cts + CB_S10 = 0x00000400, // no carrier sense during transmission CB_A = 0x00001000, // command aborted CB_OK = 0x00002000, // error free completion CB_B = 0x00004000, // busy executing command @@ -147,6 +153,7 @@ public: static const u32 SCP_ADDRESS = 0x00fffff4; // the default value of the system configuration pointer static const u32 TBD_EMPTY = 0x0000ffff; // FIXME: datasheet says this field should be "all 1's", but InterPro sets only lower 16 bits (in linear mode) static const u32 RBD_EMPTY = 0x0000ffff; + static const int MAX_FRAME_SIZE = 65536; // real device effectively has no limit, emulation relies on index wrapping static const u32 FCS_RESIDUE = 0xdebb20e3; // the residue after computing the fcs over a complete frame (including fcs) @@ -221,9 +228,10 @@ protected: u32 m_cba; // current command block address u32 m_rfd; // current receive frame descriptor address - u64 m_mac_multi; // multicast address hash table - u8 m_lb_buf[1528]; // storage for loopback frames - int m_lb_length; // length of loopback frame + u64 m_mac_multi; // multicast address hash table + + u8 m_lb_buf[MAX_FRAME_SIZE]; // storage for loopback frames + u16 m_lb_length; // length of loopback frame (relies on wrapping to match 64k max buffer size) // configure parameters enum lb_mode @@ -350,7 +358,6 @@ private: u8 m_cfg_bytes[CFG_SIZE]; u8 m_sysbus; - u32 m_iscp_address; u64 m_mac_multi_ia; // multi-ia address hash table }; -- cgit v1.2.3