mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
-bus/a2bus: Added //SHH SYSTEME LANceGS Card. (#8264)
-machine/smc91c9x.cpp adjustments: * Reset should disable promiscuous mode. * RCR - handle promiscuous changes, adjust soft reset handling. * EPH_STATUS should be LINK_OK by default (previous code wouldn't set LINK_OK unless RX_EN is set but LANceGS won't set RX_EN unless LINK_OK is set). * B0_BANK bits 4-8 are unspecified in the documentation but LANceGS expects a 3 (used in Card detection logic). * MIR values depend on device type and resets when the mmu resets. * Reading/writing the data register needs to be aware of 8-bit I/O. * Calculate FCS. * Removed WMS OUI filtering hack.
This commit is contained in:
parent
6ffc98289c
commit
a9fefd8363
@ -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",
|
||||
|
178
src/devices/bus/a2bus/lancegs.cpp
Normal file
178
src/devices/bus/a2bus/lancegs.cpp
Normal file
@ -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);
|
||||
}
|
52
src/devices/bus/a2bus/lancegs.h
Normal file
52
src/devices/bus/a2bus/lancegs.h
Normal file
@ -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<smc91c96_device> m_netinf;
|
||||
required_device<i2c_24c04_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
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user