diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 5d4df6e5730..3540bb8c6a1 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -2460,6 +2460,8 @@ if (BUSES["A2BUS"]~=null) then MAME_DIR .. "src/devices/bus/a2bus/ezcgi.h", MAME_DIR .. "src/devices/bus/a2bus/grappler.cpp", MAME_DIR .. "src/devices/bus/a2bus/grappler.h", + MAME_DIR .. "src/devices/bus/a2bus/lancegs.cpp", + MAME_DIR .. "src/devices/bus/a2bus/lancegs.h", MAME_DIR .. "src/devices/bus/a2bus/laser128.cpp", MAME_DIR .. "src/devices/bus/a2bus/laser128.h", MAME_DIR .. "src/devices/bus/a2bus/mouse.cpp", diff --git a/src/devices/bus/a2bus/lancegs.cpp b/src/devices/bus/a2bus/lancegs.cpp new file mode 100644 index 00000000000..137d76eca34 --- /dev/null +++ b/src/devices/bus/a2bus/lancegs.cpp @@ -0,0 +1,178 @@ +// license:BSD-3-Clause +// copyright-holders:Kelvin Sherlock +/********************************************************************* + + lancegs.cpp + + Apple II LANceGS Card + + Kelvin Sherlock with assistance from Geoff Weiss + + SMSC LAN 91c96 and 24c04 EEPROM + + + Bit 1 of C0nF switches between EEPROM (1) and Ethernet (0, default). + This bit is write only. + + In EEPROM Mode: + + C0n4 - Clock Low + C0n5 - Clock High + C0n6 - Data Low + C0n7 - Data High + C0n8 - Read Data + C0nF - toggle EEPROM/Ethernet + + + Known EEPROM locations. All strings high ascii, 0-terminated. + + 0x00: Identification string ("LANceGS Ethernet Card (c) 2000 Joachim Lange") + 0x30: Revision string + 0x40: Revision Code (1 byte) + 0x48: Production date, yy m d (4 bytes) + 0x4c: Service date, yy m d (4 bytes) + 0x50: Serial Number (2 bytes) + 0x60: MAC Address (6 bytes) + 0x66: Destination Mac Address (6 bytes) * + 0x80: IP Address (4 bytes) * + 0x84: Destination IP Address (4 bytes) * + 0x88: Netmask (4 bytes) * + 0x8c: Gateway (4 bytes) * + + * configurable with included software. + + +*********************************************************************/ + +#include "emu.h" +#include "lancegs.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +DEFINE_DEVICE_TYPE(A2BUS_LANCEGS, a2bus_lancegs_device, "a2lancegs", "///SHH Systeme LANceGS") + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_lancegs_device::a2bus_lancegs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + a2bus_lancegs_device(mconfig, A2BUS_LANCEGS, tag, owner, clock) +{ +} + +a2bus_lancegs_device::a2bus_lancegs_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), + device_a2bus_card_interface(mconfig, *this), + m_netinf(*this, "smc91c96"), + m_i2cmem(*this, "i2cmem"), + m_shadow(false) +{ +} + +void a2bus_lancegs_device::device_add_mconfig(machine_config &config) +{ + SMC91C96(config, m_netinf, 20_MHz_XTAL); // Datasheet fig 12.26, pg 122. + I2C_24C04(config, m_i2cmem, 0).set_address(0x80).set_e0(1); + + m_netinf->irq_handler().set(FUNC(a2bus_lancegs_device::netinf_irq_w)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_lancegs_device::device_start() +{ + save_item(NAME(m_shadow)); +} + +void a2bus_lancegs_device::device_reset() +{ + m_shadow = false; +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +uint8_t a2bus_lancegs_device::read_c0nx(uint8_t offset) +{ + if (m_shadow) { + switch(offset) { + case 0x08: /* read data */ + return 0xfe | m_i2cmem->read_sda(); + break; + case 0x0f: + return 0x33; + break; + default: + return 0xff; + break; + } + } else { + const uint16_t mask = offset & 0x01 ? 0xff00: 0x00ff; + const uint16_t value = m_netinf->read(offset >> 1, mask); + return offset & 0x01 ? value >> 8 : value; + } +} + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_lancegs_device::write_c0nx(uint8_t offset, uint8_t data) +{ + if (offset == 0x0f) { + m_shadow = data & 0x01; + return; + } + + if (m_shadow) { + switch(offset) { + case 0x04: /* set clock low */ + m_i2cmem->write_scl(0); + break; + case 0x05: /* set clock high */ + m_i2cmem->write_scl(1); + break; + case 0x06: /* set data low */ + m_i2cmem->write_sda(0); + break; + case 0x07: /* set data high */ + m_i2cmem->write_sda(1); + break; + default: + break; + } + } else { + const uint16_t mask = offset & 0x01 ? 0xff00: 0x00ff; + const uint16_t value = offset & 0x01 ? data << 8 : data; + m_netinf->write(offset >> 1, value, mask); + } +} + +WRITE_LINE_MEMBER( a2bus_lancegs_device::netinf_irq_w ) +{ + if (state) { + raise_slot_irq(); + } else { + lower_slot_irq(); + } +} + + +ROM_START(lancegs) + ROM_REGION(0x0200, "i2cmem", 0) + ROM_LOAD("lancegs.nv", 0x0000, 0x0200, NO_DUMP) +ROM_END + +const tiny_rom_entry *a2bus_lancegs_device::device_rom_region() const +{ + return ROM_NAME(lancegs); +} diff --git a/src/devices/bus/a2bus/lancegs.h b/src/devices/bus/a2bus/lancegs.h new file mode 100644 index 00000000000..2a9024296e2 --- /dev/null +++ b/src/devices/bus/a2bus/lancegs.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Kelvin Sherlock +/********************************************************************* + + lancegs.h + + Apple II LANceGS Card + +*********************************************************************/ + +#ifndef MAME_BUS_A2BUS_LANCEGS_H +#define MAME_BUS_A2BUS_LANCEGS_H + +#include "a2bus.h" +#include "machine/smc91c9x.h" +#include "machine/i2cmem.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_lancegs_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_lancegs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + a2bus_lancegs_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual void device_start() override; + virtual void device_reset() override; + + virtual uint8_t read_c0nx(uint8_t offset) override; + virtual void write_c0nx(uint8_t offset, uint8_t data) override; + +private: + required_device m_netinf; + required_device m_i2cmem; + bool m_shadow; + + DECLARE_WRITE_LINE_MEMBER( netinf_irq_w ); +}; + +// device type definition +DECLARE_DEVICE_TYPE(A2BUS_LANCEGS, a2bus_lancegs_device) + +#endif // MAME_BUS_A2BUS_LANCEGS_H diff --git a/src/devices/machine/smc91c9x.cpp b/src/devices/machine/smc91c9x.cpp index 7d85deee42b..e8bc3dda5b1 100644 --- a/src/devices/machine/smc91c9x.cpp +++ b/src/devices/machine/smc91c9x.cpp @@ -71,7 +71,6 @@ smc91c9x_device::smc91c9x_device(const machine_config &mconfig, device_type type } const u8 smc91c9x_device::ETH_BROADCAST[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -const u8 smc91c9x_device::WMS_OUI[] = { 0x00, 0xA0, 0xAF }; //------------------------------------------------- // device_start - device-specific startup @@ -95,12 +94,19 @@ void smc91c9x_device::device_start() m_reg[B1_IA2_3] = 0x0000; m_regmask[B1_IA2_3] = 0xffff; m_reg[B1_IA4_5] = 0x0000; m_regmask[B1_IA4_5] = 0xffff; - // Revision is set based on chip type + // Revision and MIR is based on chip type m_regmask[B3_REVISION] = 0x0000; + m_regmask[B0_MIR] = 0x0000; if (m_device_type == dev_type::SMC91C94) + { m_reg[B3_REVISION] = 0x3345; + m_reg[B0_MIR] = 0x1212; + } else if (m_device_type == dev_type::SMC91C96) + { m_reg[B3_REVISION] = 0x3346; + m_reg[B0_MIR] = 0x1818; + } else fatalerror("device_start: Unknown device type\n"); @@ -148,12 +154,11 @@ void smc91c9x_device::device_reset() m_tx_retry_count = 0; m_reg[B0_TCR] = 0x0000; m_regmask[B0_TCR] = 0x3d87; - m_reg[B0_EPH_STATUS] = 0x0000; m_regmask[B0_EPH_STATUS] = 0x0000; + m_reg[B0_EPH_STATUS] = 0x4000; m_regmask[B0_EPH_STATUS] = 0x0000; m_reg[B0_RCR] = 0x0000; m_regmask[B0_RCR] = 0xc307; m_reg[B0_COUNTER] = 0x0000; m_regmask[B0_COUNTER] = 0x0000; - m_reg[B0_MIR] = 0x1212; m_regmask[B0_MIR] = 0x0000; m_reg[B0_MCR] = 0x3300; m_regmask[B0_MCR] = 0x00ff; - m_reg[B0_BANK] = 0x3300; m_regmask[B0_BANK] = 0x0007; + m_reg[B0_BANK] = 0x3330; m_regmask[B0_BANK] = 0x0007; m_reg[B1_GENERAL_PURP] = 0x0000; m_regmask[B1_GENERAL_PURP] = 0xffff; m_reg[B1_CONTROL] = 0x0100; m_regmask[B1_CONTROL] = 0x68e7; @@ -174,6 +179,8 @@ void smc91c9x_device::device_reset() m_reg[B3_ERCV] = 0x331f; m_regmask[B3_ERCV] = 0x009f; + set_promisc(false); + update_ethernet_irq(); // Reset MMU @@ -186,6 +193,10 @@ void smc91c9x_device::mmu_reset() m_alloc_rx = 0; m_alloc_tx = 0; + // The register defaults to the MEMORY SIZE upon reset or upon the RESET MMU command. + m_reg[B0_MIR] &= 0xff; + m_reg[B0_MIR] |= m_reg[B0_MIR] << 8; + // Reset fifos. reset_tx_fifos(); reset_completed_rx(); @@ -394,14 +405,6 @@ int smc91c9x_device::recv_start_cb(u8 *buf, int length) return 0; } - // discard packets not from WMS - if (memcmp(WMS_OUI, &buf[6], 3)) - { - LOGMASKED(LOG_RX, "received non-WMS packet OUI: %02x:%02x:%02x length %d discarded\n", buf[6], buf[7], buf[8], length); - - return 0; - } - // Check for active transmission if (m_tx_active) { @@ -557,13 +560,14 @@ TIMER_CALLBACK_MEMBER(smc91c9x_device::tx_poll) tx_buffer[length++] = 0x00; // Add CRC - // TODO: Calculate CRC - if (1 && ((control & EBUF_CRC) || !(m_reg[B0_TCR] & NOCRC))) + if (((control & EBUF_CRC) || !(m_reg[B0_TCR] & NOCRC))) { - tx_buffer[length++] = 0x11; - tx_buffer[length++] = 0x22; - tx_buffer[length++] = 0x33; - tx_buffer[length++] = 0x44; + u32 crc = util::crc32_creator::simple(tx_buffer + 4, length - 4); + + tx_buffer[length++] = (crc >> 0) & 0xff; + tx_buffer[length++] = (crc >> 8) & 0xff; + tx_buffer[length++] = (crc >> 16) & 0xff; + tx_buffer[length++] = (crc >> 24) & 0xff; } // Remove status, length @@ -590,7 +594,7 @@ TIMER_CALLBACK_MEMBER(smc91c9x_device::tx_poll) if (m_reg[B0_TCR] & (EPH_LOOP | LOOP)) send_complete_cb(length); else - send(&tx_buffer[4], length); + send(&tx_buffer[4], length, 4); } } @@ -841,7 +845,9 @@ u16 smc91c9x_device::read(offs_t offset, u16 mem_mask) else buffer = &m_buffer[(m_reg[B2_PNR_ARR] & 0x1f) * ETHER_BUFFER_SIZE]; - result = buffer[addr++]; + result = 0; + if ( ACCESSING_BITS_0_7 ) + result = buffer[addr++]; if ( ACCESSING_BITS_8_15 ) result |= buffer[addr++] << 8; if ( m_reg[B2_POINTER] & 0x4000 ) @@ -872,8 +878,10 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask) if (offset != B0_BANK && offset < sizeof(m_reg)) LOG("%s:smc91c9x_w(%s) = [%04X]<-%04X & (%04X & %04X)\n", machine().describe_context(), ethernet_regname[offset], offset, data, mem_mask , m_regmask[offset]); + const uint16_t old_reg = m_reg[offset]; mem_mask &= m_regmask[offset]; COMBINE_DATA(&m_reg[offset]); + const uint16_t new_reg = m_reg[offset]; /* handle it */ switch (offset) @@ -911,7 +919,7 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask) reset(); } - if ( !(data & RXEN) ) + if ( (old_reg & RXEN) && !(new_reg & RXEN)) { reset_completed_rx(); } @@ -921,6 +929,11 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask) m_reg[B0_EPH_STATUS] |= LINK_OK; } + if ((old_reg ^ new_reg) & PRMS) + { + set_promisc(new_reg & PRMS); + } + if (VERBOSE & LOG_GENERAL) { if (data & SOFT_RST) LOG(" SOFT RST\n"); @@ -951,14 +964,16 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask) break; case B1_IA4_5: - set_promisc(m_reg[B0_RCR] & PRMS); - set_mac((char *)&m_reg[B1_IA0_1]); - + if ( ACCESSING_BITS_8_15 ) + { + set_promisc(m_reg[B0_RCR] & PRMS); + set_mac((char *)&m_reg[B1_IA0_1]); + } break; case B1_CONTROL: /* control register */ // Clearing LE_EN clears interrupt from LINK_OK status change - if (!(data & LE_ENABLE)) + if ( (old_reg & LE_ENABLE) && !(new_reg & LE_ENABLE)) { m_reg[B2_INTERRUPT] &= ~EINT_EPH; update_ethernet_irq(); @@ -1002,7 +1017,8 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask) else buffer = &m_buffer[(m_reg[B2_PNR_ARR] & 0x1f) * ETHER_BUFFER_SIZE]; - buffer[addr++] = data; + if ( ACCESSING_BITS_0_7 ) + buffer[addr++] = data; if ( ACCESSING_BITS_8_15 ) buffer[addr++] = data >> 8; if ( m_reg[B2_POINTER] & AUTO_INCR) diff --git a/src/devices/machine/smc91c9x.h b/src/devices/machine/smc91c9x.h index 541721eafc0..8c5aa3c2460 100644 --- a/src/devices/machine/smc91c9x.h +++ b/src/devices/machine/smc91c9x.h @@ -215,9 +215,9 @@ private: PTR = 0x07ff }; + static constexpr u32 FCS_RESIDUE = 0xdebb20e3; static constexpr unsigned ETHER_BUFFER_SIZE = 256 * 6; static const u8 ETH_BROADCAST[]; - static const u8 WMS_OUI[]; // mmu diff --git a/src/mame/drivers/apple2e.cpp b/src/mame/drivers/apple2e.cpp index bc5e2be148e..8ec2c16e64a 100644 --- a/src/mame/drivers/apple2e.cpp +++ b/src/mame/drivers/apple2e.cpp @@ -175,6 +175,7 @@ MIG RAM page 2 $CE02 is the speaker/slot bitfield and $CE03 is the paddle/accele #include "bus/a2bus/ccs7710.h" #include "bus/a2bus/ezcgi.h" #include "bus/a2bus/grappler.h" +#include "bus/a2bus/lancegs.h" #include "bus/a2bus/laser128.h" #include "bus/a2bus/mouse.h" #include "bus/a2bus/pc_xporter.h" @@ -4700,6 +4701,7 @@ static void apple2_cards(device_slot_interface &device) device.option_add("uniprint", A2BUS_UNIPRINT); /* Videx Uniprint parallel printer card */ device.option_add("ccs7710", A2BUS_CCS7710); /* California Computer Systems Model 7710 Asynchronous Serial Interface */ device.option_add("booti", A2BUS_BOOTI); /* Booti Card */ + device.option_add("lancegs", A2BUS_LANCEGS); /* ///SHH SYSTEME LANceGS Card */ } static void apple2eaux_cards(device_slot_interface &device) diff --git a/src/mame/drivers/apple2gs.cpp b/src/mame/drivers/apple2gs.cpp index 88333f6f411..5f576c4c527 100644 --- a/src/mame/drivers/apple2gs.cpp +++ b/src/mame/drivers/apple2gs.cpp @@ -115,6 +115,7 @@ #include "bus/a2bus/ezcgi.h" #include "bus/a2bus/grappler.h" //#include "bus/a2bus/hostram.h" +#include "bus/a2bus/lancegs.h" #include "bus/a2bus/laser128.h" #include "bus/a2bus/mouse.h" //#include "bus/a2bus/pc_xporter.h" @@ -4788,6 +4789,7 @@ static void apple2_cards(device_slot_interface &device) device.option_add("uniprint", A2BUS_UNIPRINT); /* Videx Uniprint parallel printer card */ device.option_add("ccs7710", A2BUS_CCS7710); /* California Computer Systems Model 7710 Asynchronous Serial Interface */ device.option_add("booti", A2BUS_BOOTI); /* Booti Card */ + device.option_add("lancegs", A2BUS_LANCEGS); /* ///SHH SYSTEME LANceGS Card */ } void apple2gs_state::apple2gs(machine_config &config)