From f7fa5c89e142aa3fd6d4afebb6dbe49a68b2c868 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Tue, 2 Apr 2019 09:57:16 +0700 Subject: [PATCH] 3c505: added lle [Patrick Mackinlay, Neko May] LLE implementation of 3Com 3c505. Untested due to unresolved driver issues, but should replace existing HLE when tested working. (nw) --- src/devices/bus/isa/3c505.cpp | 650 ++++++++++++++++++++++++++++++ src/devices/bus/isa/3c505.h | 133 ++++++ src/devices/bus/isa/isa_cards.cpp | 1 + 3 files changed, 784 insertions(+) diff --git a/src/devices/bus/isa/3c505.cpp b/src/devices/bus/isa/3c505.cpp index 37cd5ef346a..6eb4a99e8b8 100644 --- a/src/devices/bus/isa/3c505.cpp +++ b/src/devices/bus/isa/3c505.cpp @@ -299,6 +299,7 @@ constexpr unsigned threecom3c505_device::ETH_BUFFER_SIZE; // device type definition DEFINE_DEVICE_TYPE(ISA16_3C505, threecom3c505_device, "3c505", "3Com 3C505 Network Adaptor") +DEFINE_DEVICE_TYPE(ISA16_3C505_LLE, isa16_3c505_device, "3c505_lle", "3Com EtherLink Plus") //------------------------------------------------- // threecom3c505_device - constructor @@ -1686,3 +1687,652 @@ int threecom3c505_device::setfilter(device_t *device, int node_id) { return 0; } + +/* + * The following device is a low-level reimplementation of the 3c505, which + * should entirely replace the HLE one above when it's been tested and proven + * working. + * + * TODO + * - testing (unable to install Domain/OS on Apollo, and not yet able to get + * 3c505.exe diagnostic program running on MS-DOS) + * - data DMA functionality unimplemented + * - externalize mac address + * - 8 bit isa slot support + * - revision 1.0 and 2.0 hardware/firmware variants + * - 8023 loopback mode + */ + +#undef LOG +#undef VERBOSE + +#define LOG_GENERAL (1U << 0) +#define LOG_REG (1U << 1) + +#define VERBOSE (0) +#include "logmacro.h" + +ROM_START(3c505) + ROM_REGION16_LE(0x04000, "system", 0) + // TODO: probably a revision 3.0 firmware dump + ROMX_LOAD("0729-12_a.3h", 0x00000, 0x02000, CRC(5415fccd) SHA1(6a42d7f3acdb3e0213e1037fee1864819ac33991), ROM_SKIP(1)) + ROMX_LOAD("0729-62_a.3f", 0x00001, 0x02000, CRC(4240bd9d) SHA1(015d2f7282def85681bcf1a7c5a7f501a16d5a6c), ROM_SKIP(1)) + + ROM_REGION(0x02000, "host", 0) + ROM_SYSTEM_BIOS(0, "unused", "Unused") + + ROM_SYSTEM_BIOS(1, "apollo", "Apollo") + ROMX_LOAD("3000_3c505_010728-00.bin", 0x00000, 0x02000, CRC(69b77ec6) SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58), ROM_BIOS(1)) + + ROM_SYSTEM_BIOS(2, "netware", "3C505-NW EtherLink Plus NetWare Boot PROM") + ROMX_LOAD("3c505-nw.bin", 0x00000, 0x02000, NO_DUMP, ROM_BIOS(2)) +ROM_END + +static INPUT_PORTS_START(3c505) + PORT_START("IO_BASE") + PORT_DIPNAME(0x3f0, 0x300, "I/O Base") + PORT_DIPSETTING( 0x010, "010h") + PORT_DIPSETTING( 0x020, "020h") + PORT_DIPSETTING( 0x030, "030h") + PORT_DIPSETTING( 0x040, "040h") + PORT_DIPSETTING( 0x050, "050h") + PORT_DIPSETTING( 0x060, "060h") + PORT_DIPSETTING( 0x070, "070h") + PORT_DIPSETTING( 0x080, "080h") + PORT_DIPSETTING( 0x090, "090h") + PORT_DIPSETTING( 0x0a0, "0a0h") + PORT_DIPSETTING( 0x0b0, "0b0h") + PORT_DIPSETTING( 0x0c0, "0c0h") + PORT_DIPSETTING( 0x0d0, "0d0h") + PORT_DIPSETTING( 0x0e0, "0e0h") + PORT_DIPSETTING( 0x0f0, "0f0h") + PORT_DIPSETTING( 0x100, "0100h") + PORT_DIPSETTING( 0x110, "0110h") + PORT_DIPSETTING( 0x120, "0120h") + PORT_DIPSETTING( 0x130, "0130h") + PORT_DIPSETTING( 0x140, "0140h") + PORT_DIPSETTING( 0x150, "0150h") + PORT_DIPSETTING( 0x160, "0160h") + PORT_DIPSETTING( 0x170, "0170h") + PORT_DIPSETTING( 0x180, "0180h") + PORT_DIPSETTING( 0x190, "0190h") + PORT_DIPSETTING( 0x1a0, "01a0h") + PORT_DIPSETTING( 0x1b0, "01b0h") + PORT_DIPSETTING( 0x1c0, "01c0h") + PORT_DIPSETTING( 0x1d0, "01d0h") + PORT_DIPSETTING( 0x1e0, "01e0h") + PORT_DIPSETTING( 0x1f0, "01f0h") + PORT_DIPSETTING( 0x200, "0200h") + PORT_DIPSETTING( 0x210, "0210h") + PORT_DIPSETTING( 0x220, "0220h") + PORT_DIPSETTING( 0x230, "0230h") + PORT_DIPSETTING( 0x240, "0240h") + PORT_DIPSETTING( 0x250, "0250h") + PORT_DIPSETTING( 0x260, "0260h") + PORT_DIPSETTING( 0x270, "0270h") + PORT_DIPSETTING( 0x280, "0280h") + PORT_DIPSETTING( 0x290, "0290h") + PORT_DIPSETTING( 0x2a0, "02a0h") + PORT_DIPSETTING( 0x2b0, "02b0h") + PORT_DIPSETTING( 0x2c0, "02c0h") + PORT_DIPSETTING( 0x2d0, "02d0h") + PORT_DIPSETTING( 0x2e0, "02e0h") + PORT_DIPSETTING( 0x2f0, "02f0h") + PORT_DIPSETTING( 0x300, "0300h") + PORT_DIPSETTING( 0x310, "0310h") + PORT_DIPSETTING( 0x320, "0320h") + PORT_DIPSETTING( 0x330, "0330h") + PORT_DIPSETTING( 0x340, "0340h") + PORT_DIPSETTING( 0x350, "0350h") + PORT_DIPSETTING( 0x360, "0360h") + PORT_DIPSETTING( 0x370, "0370h") + PORT_DIPSETTING( 0x380, "0380h") + PORT_DIPSETTING( 0x390, "0390h") + PORT_DIPSETTING( 0x3a0, "03a0h") + PORT_DIPSETTING( 0x3b0, "03b0h") + PORT_DIPSETTING( 0x3c0, "03c0h") + PORT_DIPSETTING( 0x3d0, "03d0h") + PORT_DIPSETTING( 0x3e0, "03e0h") + PORT_DIPSETTING( 0x3f0, "03f0h") + + PORT_START("IRQ_DRQ") + PORT_DIPNAME(0x0f, 0x0a, "IRQ") + // 8 or 16 bit slots + PORT_DIPSETTING( 0x03, "IRQ 3") + PORT_DIPSETTING( 0x04, "IRQ 4") + PORT_DIPSETTING( 0x05, "IRQ 5") + PORT_DIPSETTING( 0x06, "IRQ 6") + PORT_DIPSETTING( 0x07, "IRQ 7") + PORT_DIPSETTING( 0x09, "IRQ 9") + // 16 bit slots only + PORT_DIPSETTING( 0x0a, "IRQ 10") + PORT_DIPSETTING( 0x0b, "IRQ 11") + PORT_DIPSETTING( 0x0c, "IRQ 12") + PORT_DIPSETTING( 0x0e, "IRQ 14") + PORT_DIPSETTING( 0x0f, "IRQ 15") + + // TODO: dma channel uses two jumpers for each channel: mode selection? + PORT_DIPNAME(0x70, 0x60, "DRQ") + PORT_DIPSETTING( 0x00, "none") + // 8 or 16 bit slots + PORT_DIPSETTING( 0x10, "DRQ 1") + PORT_DIPSETTING( 0x30, "DRQ 3") + // 16 bit slots only + PORT_DIPSETTING( 0x50, "DRQ 5") + PORT_DIPSETTING( 0x60, "DRQ 6") + PORT_DIPSETTING( 0x70, "DRQ 7") + + // 8-position jumper block marked EN,13-19 corresponds to address line decode + PORT_START("ROM_OPTS") + PORT_DIPNAME(0x01, 0x01, "ROM Enable") + PORT_DIPSETTING( 0x00, DEF_STR(Off)) + PORT_DIPSETTING( 0x01, DEF_STR(On)) + PORT_DIPNAME(0xfe, 0x00, "ROM Base") + PORT_DIPSETTING( 0x00, "0000h") + PORT_DIPSETTING( 0x02, "2000h") + PORT_DIPSETTING( 0x04, "4000h") + PORT_DIPSETTING( 0x06, "6000h") + // TODO: additional addresses + + PORT_START("TEST") + PORT_DIPNAME(0x01, 0x00, "TEST Mode") + PORT_DIPSETTING( 0x00, DEF_STR(Off)) + PORT_DIPSETTING( 0x01, DEF_STR(On)) +INPUT_PORTS_END + +isa16_3c505_device::isa16_3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, ISA16_3C505_LLE, tag, owner, clock) + , device_isa16_card_interface(mconfig, *this) + , m_cpu(*this, "cpu") + , m_net(*this, "net") + , m_ram(*this, "ram") + , m_led(*this, "led%u", 0U) + , m_iobase(*this, "IO_BASE") + , m_irqdrq(*this, "IRQ_DRQ") + , m_romopts(*this, "ROM_OPTS") + , m_test(*this, "TEST") + , m_installed(false) +{ +} + +const tiny_rom_entry *isa16_3c505_device::device_rom_region() const +{ + return ROM_NAME(3c505); +} + +void isa16_3c505_device::device_add_mconfig(machine_config &config) +{ + I80186(config, m_cpu, 16_MHz_XTAL); + m_cpu->set_addrmap(AS_PROGRAM, &isa16_3c505_device::map_main); + m_cpu->set_addrmap(AS_IO, &isa16_3c505_device::map_io); + + I82586(config, m_net, 8_MHz_XTAL); + m_net->set_addrmap(0, &isa16_3c505_device::map_main); + m_net->out_irq_cb().set(m_cpu, FUNC(i80186_cpu_device::int1_w)); + + // 1986 document indicates 128KiB is default, but 1988 document does not + // include it as an option + RAM(config, m_ram); + m_ram->set_default_size("256KiB"); + m_ram->set_extra_options("128KiB,256KiB,384KiB,512KiB"); +} + +ioport_constructor isa16_3c505_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(3c505); +} + +void isa16_3c505_device::device_start() +{ + set_isa_device(); + + // install ram in both i80186 and i82586 address spaces + if (!m_ram->started()) + throw device_missing_dependencies(); + + m_cpu->space(0).install_ram(0x00000, m_ram->mask() & 0xfffff, m_ram->pointer()); + m_net->space(0).install_ram(0x00000, m_ram->mask() & 0xfffff, m_ram->pointer()); + + m_led.resolve(); + + save_item(NAME(m_acmdr)); + save_item(NAME(m_acr)); + save_item(NAME(m_asr)); + + save_item(NAME(m_hcmdr)); + save_item(NAME(m_hcr)); + save_item(NAME(m_hsr)); + save_item(NAME(m_hdr)); + + //save_item(NAME(m_data); + + save_item(NAME(m_cpu_irq_asserted)); + save_item(NAME(m_isa_irq_asserted)); +} + +void isa16_3c505_device::device_reset() +{ + if (!m_installed) + { + u16 const base = m_iobase->read(); + m_isa->install16_device(base, base | 0xf, + read16_delegate(FUNC(isa16_3c505_device::host_r), this), + write16_delegate(FUNC(isa16_3c505_device::host_w), this)); + + m_isa_irq = m_irqdrq->read() & 0xf; + m_isa_drq = (m_irqdrq->read() >> 4) & 0x7; + + if (m_romopts->read() & 1) + { + offs_t const rom_base = (m_romopts->read() & 0xfe) << 12; + + m_isa->install_rom(this, rom_base, rom_base | 0x01fff, "host", "host"); + } + + m_installed = true; + } + + m_cpu->reset(); + + // adapter registers + m_acmdr = 0; + m_acr = 0; + m_asr = ASR_ACRE | ASR_8_16; + if (m_test->read()) + m_asr |= ASR_SWTC; + + // host registers + m_hcmdr = 0; + m_hcr = 0; + m_hsr = HSR_HCRE; + m_hdr = 0; + + m_data.clear(); + update_rdy(m_acr, m_hcr); + + m_cpu_irq_asserted = false; + m_isa_irq_asserted = false; +} + +void isa16_3c505_device::map_main(address_map &map) +{ + // i82586 upper 4 address lines are ignored + map.global_mask(0x0fffff); + + map(0xfc000, 0xfffff).rom().region("system", 0); +} + +void isa16_3c505_device::map_io(address_map &map) +{ + /* + * A read or write to I/O location 00H will cause an active transition on + * the CA input. + */ + map(0x0000, 0x0000).lrw8("ca", + [this]() + { + m_net->ca(1); + m_net->ca(0); + + return 0; + }, + [this](u8 data) + { + m_net->ca(1); + m_net->ca(0); + }); + + /* + * A read or write to I/O location 80H will produce a CAS before RAS cycle + * in all banks simultaneously. + */ + map(0x0080, 0x0081).noprw(); + + map(0x0100, 0x0100).rw(FUNC(isa16_3c505_device::acmd_r), FUNC(isa16_3c505_device::acmd_w)); + map(0x0102, 0x0102).r(FUNC(isa16_3c505_device::acr_r)); + map(0x0103, 0x0103).rw(FUNC(isa16_3c505_device::asr_r), FUNC(isa16_3c505_device::acr_w)); + map(0x0104, 0x0105).rw(FUNC(isa16_3c505_device::adata_r), FUNC(isa16_3c505_device::adata_w)); + + map(0x0180, 0x018f).lr16("mac", + [](offs_t offset) + { + // TODO: hard-code to Apollo Computer Inc. dummy address for now + static const u8 mac[] = { 0x08, 0x00, 0x1e, 0x12, 0x34, 0x56, 0xff, 0xff}; + + return mac[offset]; + }); +} + +u8 isa16_3c505_device::acmd_r() +{ + u8 const data = m_hcmdr; + + m_asr &= ~ASR_HCRF; + m_hsr |= HSR_HCRE; + + if (m_cpu_irq_asserted) + { + m_cpu_irq_asserted = false; + m_cpu->int0_w(0); + } + + return data; +} + +void isa16_3c505_device::acmd_w(u8 data) +{ + LOGMASKED(LOG_REG, "acmd_w 0x%02x (%s)\n", data, machine().describe_context()); + + m_asr &= ~ASR_ACRE; + m_hsr |= HSR_ACRF; + + m_acmdr = data; + + if (m_hcr & HCR_CMDE) + update_irq(1); +} + +void isa16_3c505_device::acr_w(u8 data) +{ + LOGMASKED(LOG_REG, "acr_w 0x%02x (%s)\n", data, machine().describe_context()); + + // update adapter status flags + if ((data ^ m_acr) & ACR_ASF) + m_hsr = (m_hsr & ~HSR_ASF) | (data & ACR_ASF); + + if ((data ^ m_acr) & ACR_LED1) + { + LOGMASKED(LOG_REG, "led #1 %s\n", (data & ACR_LED1) ? "on" : "off"); + m_led[0] = !!(data & ACR_LED1); + } + + if ((data ^ m_acr) & ACR_LED2) + { + LOGMASKED(LOG_REG, "led #2 %d\n", (data & ACR_LED2) ? "on" : "off"); + m_led[1] = !!(data & ACR_LED2); + } + + if (!(m_acr & ACR_R586) && (data & ACR_R586)) + { + LOGMASKED(LOG_REG, "i82586 reset\n"); + m_net->reset(); + } + + if ((data ^ m_acr) & ACR_FLSH) + { + if (data & ACR_FLSH) + { + LOGMASKED(LOG_REG, "adapter flushed data fifo (%d bytes)\n", m_data.queue_length()); + m_data.clear(); + } + + update_rdy(data, m_hcr); + } + + // loopback is active low + if ((m_acr & ACR_LPBK) && !(data & ACR_LPBK)) + { + LOGMASKED(LOG_REG, "loopback enabled\n", m_data.queue_length()); + + // TODO: enable loopback on 8023 + } + + m_acr = data; +} + +u16 isa16_3c505_device::adata_r() +{ + if (!(m_asr & ASR_DIR) && !m_data.empty()) + { + u16 const data = m_data.dequeue(); + + update_rdy(m_acr, m_hcr); + + return data; + } + else + fatalerror("%s: adata_r read fifo while %s (%s)\n", + tag(), m_data.empty() ? "empty" : "write-only", machine().describe_context().c_str()); +} + +void isa16_3c505_device::adata_w(u16 data) +{ + if ((m_asr & ASR_DIR) && !m_data.full()) + { + m_data.enqueue(data); + + update_rdy(m_acr, m_hcr); + } + else + fatalerror("%s: adata_w write fifo while %s (%s)\n", + tag(), m_data.full() ? "full" : "read-only", machine().describe_context().c_str()); +} + +READ16_MEMBER(isa16_3c505_device::host_r) +{ + switch (offset) + { + case 0: return hcmd_r(); + case 1: return m_hsr; + case 2: return hdata_r(); + case 3: return m_hcr; + } + + logerror("host_r unknown register %d (%s)\n", offset, machine().describe_context()); + return space.unmap(); +} + +WRITE16_MEMBER(isa16_3c505_device::host_w) +{ + switch (offset) + { + case 0: + hcmd_w(data); + break; + + case 1: + m_hdr = data & HDR_BRST; + break; + + case 2: + hdata_w(data); + break; + + case 3: + hcr_w(data); + break; + + default: + logerror("host_w unknown register %d data 0x%04x (%s)\n", offset, data, machine().describe_context()); + break; + } +} + +u8 isa16_3c505_device::hcmd_r() +{ + u8 const data = m_acmdr; + + m_asr |= ASR_ACRE; + m_hsr &= ~HSR_ACRF; + + update_irq(0); + + return data; +} + +void isa16_3c505_device::hcmd_w(u8 data) +{ + LOGMASKED(LOG_REG, "hcmd_w 0x%02x (%s)\n", data, machine().describe_context()); + + m_asr |= ASR_HCRF; + m_hsr &= ~HSR_HCRE; + + m_hcmdr = data; + + if (!m_cpu_irq_asserted) + { + m_cpu_irq_asserted = true; + m_cpu->int0_w(1); + } +} + +void isa16_3c505_device::hcr_w(u8 data) +{ + LOGMASKED(LOG_REG, "hcr_w 0x%02x (%s)\n", data, machine().describe_context()); + + // update host status flags + if ((data ^ m_hcr) & HCR_HSF) + m_asr = (m_asr & ~ASR_HSF) | (data & HCR_HSF); + + // update direction flag + if ((data ^ m_hcr) & HCR_DIR) + { + if (data & HCR_DIR) + { + LOGMASKED(LOG_REG, "transfer from host to adapter\n"); + + // transfer from host to adapter + m_hsr |= HSR_DIR; + m_asr |= ASR_DIR; + + update_rdy(m_acr, data); + } + else + { + LOGMASKED(LOG_REG, "transfer from adapter to host\n"); + + // transfer from adapter to host + m_hsr &= ~HSR_DIR; + m_asr &= ~ASR_DIR; + + update_rdy(m_acr, data); + } + } + + if ((data ^ m_hcr) & HCR_FLSH) + { + if (data & HCR_FLSH) + { + LOGMASKED(LOG_REG, "host flushed data fifo (%d bytes)\n", m_data.queue_length()); + m_data.clear(); + } + + update_rdy(m_acr, data); + } + + // attention condition + if (!(m_hcr & HCR_ATTN) && (data & HCR_ATTN)) + { + if (!(data & HCR_FLSH)) + { + LOGMASKED(LOG_REG, "soft reset\n"); + + // soft reset + m_cpu->set_input_line(INPUT_LINE_NMI, 1); + m_cpu->set_input_line(INPUT_LINE_NMI, 0); + } + else + { + LOGMASKED(LOG_REG, "hard reset\n"); + + // hard reset + reset(); + } + } + + m_hcr = data; +} + +u16 isa16_3c505_device::hdata_r() +{ + if ((m_hsr & HSR_DIR) && !m_data.empty()) + { + u16 const data = m_data.dequeue(); + + update_rdy(m_acr, m_hcr); + + return data; + } + else + fatalerror("%s: hdata_r read fifo while %s (%s)\n", + tag(), m_data.empty() ? "empty" : "write-only", machine().describe_context().c_str()); +} + +void isa16_3c505_device::hdata_w(u16 data) +{ + if (!(m_hsr & HSR_DIR) && !m_data.full()) + { + m_data.enqueue(data); + + update_rdy(m_acr, m_hcr); + } + else + fatalerror("%s: hdata_w write fifo while %s (%s)\n", + tag(), m_data.full() ? "full" : "read-only", machine().describe_context().c_str()); +} + +void isa16_3c505_device::update_rdy(u8 const acr, u8 const hcr) +{ + if (!(acr & ACR_FLSH) && !(hcr & HCR_FLSH)) + { + if (hcr & HCR_DIR) + { + // adapter to host + if (m_data.empty()) + m_hsr &= ~HSR_HRDY; + else + m_hsr |= HSR_HRDY; + + if (m_data.full()) + m_asr &= ~ASR_ARDY; + else + m_asr |= ASR_ARDY; + } + else + { + // host to adapter + if (m_data.empty()) + m_asr &= ~ASR_ARDY; + else + m_asr |= ASR_ARDY; + + if (m_data.full()) + m_hsr &= ~HSR_HRDY; + else + m_hsr |= HSR_HRDY; + } + } + else + { + m_asr &= ~ASR_ARDY; + m_hsr &= ~HSR_HRDY; + } +} + +void isa16_3c505_device::update_irq(int state) +{ + if (bool(state) != m_isa_irq_asserted) + { + LOG("isa irq %d\n", state); + + switch (m_isa_irq) + { + case 3: m_isa->irq3_w(state); break; + case 4: m_isa->irq4_w(state); break; + case 5: m_isa->irq5_w(state); break; + case 6: m_isa->irq6_w(state); break; + case 7: m_isa->irq7_w(state); break; + case 9: m_isa->irq2_w(state); break; + case 10: m_isa->irq10_w(state); break; + case 11: m_isa->irq11_w(state); break; + case 12: m_isa->irq12_w(state); break; + case 14: m_isa->irq14_w(state); break; + case 15: m_isa->irq15_w(state); break; + + default: + fatalerror("%s: invalid isa irq %d\n", tag(), m_isa_irq); + } + + m_isa_irq_asserted = bool(state); + } +} diff --git a/src/devices/bus/isa/3c505.h b/src/devices/bus/isa/3c505.h index efdbe7dc7de..afb09cc32f2 100644 --- a/src/devices/bus/isa/3c505.h +++ b/src/devices/bus/isa/3c505.h @@ -13,6 +13,10 @@ #pragma once +#include "cpu/i86/i186.h" +#include "machine/i82586.h" +#include "machine/ram.h" + #include "bus/isa/isa.h" // ======================> PCB data structure @@ -276,7 +280,136 @@ private: int m_irq, m_drq; }; +class isa16_3c505_device + : public device_t + , public device_isa16_card_interface +{ +public: + isa16_3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + DECLARE_READ16_MEMBER(host_r); + DECLARE_WRITE16_MEMBER(host_w); + +protected: + // device_t overrides + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_start() override; + virtual void device_reset() override; + + void map_main(address_map &map); + void map_io(address_map &map); + + enum acr_mask : u8 + { + ACR_ASF1 = 0x01, // adapter status flag 1 + ACR_ASF2 = 0x02, // adapter status flag 2 + ACR_ASF3 = 0x04, // adapter status flag 3 + ACR_LED1 = 0x08, // led control 1 + ACR_LED2 = 0x10, // led control 2 + ACR_R586 = 0x20, // reset 82586 + ACR_FLSH = 0x40, // flush data register + ACR_LPBK = 0x80, // loopback control + + ACR_ASF = 0x07, + }; + enum asr_mask : u8 + { + ASR_HSF1 = 0x01, // host status flag 1 + ASR_HSF2 = 0x02, // host status flag 2 + ASR_SWTC = 0x04, // external switch + ASR_8_16 = 0x08, // 8/16 bit + ASR_DIR = 0x10, // direction flag + ASR_HCRF = 0x20, // host command register full + ASR_ACRE = 0x40, // adapter command register empty + ASR_ARDY = 0x80, // data register ready + + ASR_HSF = 0x03, + }; + enum hcr_mask : u8 + { + HCR_HSF1 = 0x01, // host status flag 1 + HCR_HSF2 = 0x02, // host status flag 2 + HCR_CMDE = 0x04, // command register interrupt enable + HCR_TCEN = 0x08, // terminal count interrupt enable + HCR_DIR = 0x10, // direction flag + HCR_DMAE = 0x20, // dma enable + HCR_FLSH = 0x40, // flush data register + HCR_ATTN = 0x80, // attention + + HCR_HSF = 0x03, + }; + enum hsr_mask : u8 + { + HSR_ASF1 = 0x01, // adapter status flag 1 + HSR_ASF2 = 0x02, // adapter status flag 2 + HSR_ASF3 = 0x04, // adapter status flag 3 + HSR_DONE = 0x08, // dma done + HSR_DIR = 0x10, // direction + HSR_ACRF = 0x20, // adapter command register full + HSR_HCRE = 0x40, // host command register empty + HSR_HRDY = 0x80, // data register ready + + HSR_ASF = 0x07, + }; + enum hdr_mask : u8 + { + HDR_BRST = 0x01, // dma burst + }; + + // adapter register helpers + u8 acmd_r(); + u8 acr_r() { return m_acr; }; + u8 asr_r() { return m_asr; }; + u16 adata_r(); + void acmd_w(u8 data); + void acr_w(u8 data); + void adata_w(u16 data); + + // host register helpers + u8 hcmd_r(); + u16 hdata_r(); + void hcmd_w(u8 data); + void hcr_w(u8 data); + void hdata_w(u16 data); + + void update_irq(int state); + void update_rdy(u8 const acr, u8 const hcr); + +private: + required_device m_cpu; + required_device m_net; + required_device m_ram; + + output_finder<2> m_led; + + required_ioport m_iobase; + required_ioport m_irqdrq; + required_ioport m_romopts; + required_ioport m_test; + + u8 m_acmdr; // adapter command register + u8 m_acr; // adapter control register + u8 m_asr; // adapter status register + + u8 m_hcmdr; // host command register + u8 m_hcr; // host control register + u8 m_hsr; // host status register + u8 m_hdr; // host aux dma register + + util::fifo m_data; + + unsigned m_isa_irq; + unsigned m_isa_drq; + + bool m_cpu_irq_asserted; + bool m_isa_irq_asserted; + bool m_installed; +}; + // device type definition DECLARE_DEVICE_TYPE(ISA16_3C505, threecom3c505_device) +DECLARE_DEVICE_TYPE(ISA16_3C505_LLE, isa16_3c505_device) #endif // MAME_BUS_ISA_3C505_H diff --git a/src/devices/bus/isa/isa_cards.cpp b/src/devices/bus/isa/isa_cards.cpp index 5b0c2315f38..6c06beabb5e 100644 --- a/src/devices/bus/isa/isa_cards.cpp +++ b/src/devices/bus/isa/isa_cards.cpp @@ -176,6 +176,7 @@ void pc_isa16_cards(device_slot_interface &device) device.option_add("gfxultrap", ISA16_SVGA_GFXULTRAPRO); device.option_add("tgui9680",ISA16_SVGA_TGUI9680); device.option_add("3c505", ISA16_3C505); + device.option_add("3c505_lle", ISA16_3C505_LLE); device.option_add("mach64", ISA16_SVGA_MACH64); device.option_add("sb16_lle", ISA16_SB16); device.option_add("mcd", ISA16_MCD);