Merge pull request #2631 from pmackinlay/i82586

i82586: fixed 82586 initialisation
This commit is contained in:
R. Belmont 2017-09-05 14:42:08 -04:00 committed by GitHub
commit 1908ac9eee
2 changed files with 38 additions and 26 deletions

View File

@ -13,7 +13,7 @@
* *
* This implementation should cover all of the above reasonably well, but * This implementation should cover all of the above reasonably well, but
* no testing of big endian mode in particular, and very limited testing * 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: * Some documents covering the above include:
* *
@ -22,7 +22,7 @@
* https://www.intel.com/assets/pdf/general/82596ca.pdf * https://www.intel.com/assets/pdf/general/82596ca.pdf
* *
* TODO * 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 * - more complete statistics capturing
* - 82596 monitor mode * - 82596 monitor mode
* - throttle timers and diagnostic command * - throttle timers and diagnostic command
@ -419,8 +419,10 @@ void i82586_base_device::cu_execute()
break; break;
case CB_TRANSMIT: 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)) if (cu_transmit(cb_cs))
cb_cs |= CB_OK; cb_cs |= CB_OK | CB_S6;
break; break;
case CB_TDREFLECT: case CB_TDREFLECT:
@ -758,14 +760,18 @@ void i82586_device::device_reset()
void i82586_device::initialise() 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);
m_scb_base = m_space->read_dword(m_scp_address + 4); u16 scb_offset = m_space->read_word(iscp_address + 2);
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); 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 // clear iscp busy byte
m_space->write_byte(m_scp_address, 0); m_space->write_byte(iscp_address, 0);
m_cx = true; m_cx = true;
m_cna = true; m_cna = true;
@ -890,9 +896,9 @@ bool i82586_device::cu_transmit(u32 command)
{ {
u16 tbd_count; u16 tbd_count;
// ethernet frame buffer (rounded up to 8 byte boundary) // ethernet frame buffer
u8 buf[1528]; u8 buf[MAX_FRAME_SIZE];
int length = 0; u16 length = 0;
u16 tbd_offset = m_space->read_word(m_cba + 6); 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_cfg_bytes));
save_item(NAME(m_sysbus)); save_item(NAME(m_sysbus));
save_item(NAME(m_iscp_address));
save_item(NAME(m_mac_multi_ia)); save_item(NAME(m_mac_multi_ia));
} }
@ -1230,9 +1235,9 @@ void i82596_device::port(u32 data)
void i82596_device::initialise() 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_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", 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, m_sysbus,
@ -1241,29 +1246,29 @@ void i82596_device::initialise()
m_sysbus & SYSBUS_LOCK ? "disabled" : "enabled", m_sysbus & SYSBUS_LOCK ? "disabled" : "enabled",
m_sysbus & SYSBUS_INT ? "low" : "high", m_sysbus & SYSBUS_INT ? "low" : "high",
m_sysbus & SYSBUS_BE ? "B" : "A1"); 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()) switch (mode())
{ {
case MODE_82586: case MODE_82586:
case MODE_32SEGMENTED: 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; 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); LOG("initialise scb base address 0x%08x offset 0x%04x address 0x%08x\n", m_scb_base, scb_offset, m_scb_address);
} }
break; break;
case MODE_LINEAR: 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); LOG("initialise scb address 0x%08x\n", m_scb_address);
break; break;
} }
// clear iscp busy byte // clear iscp busy byte
m_space->write_byte(m_iscp_address, 0); m_space->write_byte(iscp_address, 0);
m_cx = true; m_cx = true;
m_cna = true; m_cna = true;
@ -1505,9 +1510,9 @@ bool i82596_device::cu_transmit(u32 command)
u32 tbd_address; u32 tbd_address;
u16 tcb_count, tbd_count; u16 tcb_count, tbd_count;
// ethernet frame buffer (rounded up to 8 byte boundary) // ethernet frame buffer
u8 buf[1528]; u8 buf[MAX_FRAME_SIZE];
int length = 0; u16 length = 0;
// need offset into tcb for linear mode // need offset into tcb for linear mode
int offset = mode() == MODE_LINEAR ? 4 : 0; int offset = mode() == MODE_LINEAR ? 4 : 0;

View File

@ -70,7 +70,13 @@ public:
enum cu_cb_cs_mask 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_A = 0x00001000, // command aborted
CB_OK = 0x00002000, // error free completion CB_OK = 0x00002000, // error free completion
CB_B = 0x00004000, // busy executing command 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 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 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 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) 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_cba; // current command block address
u32 m_rfd; // current receive frame descriptor address u32 m_rfd; // current receive frame descriptor address
u64 m_mac_multi; // multicast address hash table 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 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 // configure parameters
enum lb_mode enum lb_mode
@ -350,7 +358,6 @@ private:
u8 m_cfg_bytes[CFG_SIZE]; u8 m_cfg_bytes[CFG_SIZE];
u8 m_sysbus; u8 m_sysbus;
u32 m_iscp_address;
u64 m_mac_multi_ia; // multi-ia address hash table u64 m_mac_multi_ia; // multi-ia address hash table
}; };