diff options
Diffstat (limited to 'src/devices/machine/fdc37c665gt.cpp')
-rw-r--r-- | src/devices/machine/fdc37c665gt.cpp | 457 |
1 files changed, 425 insertions, 32 deletions
diff --git a/src/devices/machine/fdc37c665gt.cpp b/src/devices/machine/fdc37c665gt.cpp index 2f2adb42976..feeec63a201 100644 --- a/src/devices/machine/fdc37c665gt.cpp +++ b/src/devices/machine/fdc37c665gt.cpp @@ -1,58 +1,451 @@ // license:BSD-3-Clause -// copyright-holders:smf +// copyright-holders: Samuele Zannoli, windyfairy +/*************************************************************************** + +FDC37C665GT.h + +SMSC FDC37C665GT High Performance Multi-Mode Parallel Port Super I/O Floppy Disk Controllers + +***************************************************************************/ + #include "emu.h" #include "fdc37c665gt.h" -fdc37c665gt_device::fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, FDC37C665GT, tag, owner, clock), - m_uart1(*this, "uart1"), - m_uart2(*this, "uart2") +#define LOG_CONFIG (1U << 1) // Show global configuration changes + +#define VERBOSE (LOG_GENERAL | LOG_CONFIG) +// #define LOG_OUTPUT_STREAM std::cout + +#include "logmacro.h" + +#define LOGCONFIG(...) LOGMASKED(LOG_CONFIG, __VA_ARGS__) + +DEFINE_DEVICE_TYPE(FDC37C665GT, fdc37c665gt_device, "fdc37c665gt", "FDC37C665GT") + +fdc37c665gt_device::fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, upd765_family_device::mode_t floppy_mode) + : device_t(mconfig, FDC37C665GT, tag, owner, clock) + , mode(OperatingMode::Run) + , config_key_step(0) + , config_index(0) + , m_floppy_mode(floppy_mode) + , m_fintr_callback(*this) + , m_fdrq_callback(*this) + , m_pintr1_callback(*this) + , m_irq3_callback(*this) + , m_irq4_callback(*this) + , m_txd1_callback(*this) + , m_ndtr1_callback(*this) + , m_nrts1_callback(*this) + , m_txd2_callback(*this) + , m_ndtr2_callback(*this) + , m_nrts2_callback(*this) + , m_fdc(*this, "fdc") + , m_serial(*this, "uart%u", 1) + , m_lpt(*this, "lpt") { } -READ8_MEMBER(fdc37c665gt_device::read) +void fdc37c665gt_device::device_start() { - uint8_t data = 0; + // Configuration registers and related bits aren't affected by soft resets + // Default addresses + com_addresses[0] = 0x3f8; + com_addresses[1] = 0x2f8; + com_addresses[2] = 0x338; + com_addresses[3] = 0x238; + + device_addresses[LogicalDevice::IDE] = 0x1f0; + device_addresses[LogicalDevice::FDC] = 0x3f0; + device_addresses[LogicalDevice::Parallel] = 0x278; + device_addresses[LogicalDevice::Serial1] = 0; // COM port + device_addresses[LogicalDevice::Serial2] = 1; // COM port - if ((offset & 0x3f8) == 0x3f8) - { - data = m_uart1->ins8250_r(offset & 7); + const uint8_t configuration_registers_defaults[] = { + 0x3b, 0x9f, 0xdc, 0x78, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x01, 0x00 + }; + + // Set the value first and then use write_configuration_register because some flags + // rely on other flags being initialized properly first + std::copy(std::begin(configuration_registers_defaults), std::end(configuration_registers_defaults), std::begin(configuration_registers)); + for (int i = 0; i < std::size(configuration_registers_defaults); i++) { + write_configuration_register(i, configuration_registers_defaults[i]); } - else if ((offset & 0x3f8) == 0x2f8) - { - data = m_uart2->ins8250_r(offset & 7); +} + +void fdc37c665gt_device::device_add_mconfig(machine_config &config) +{ + // floppy disc controller + N82077AA(config, m_fdc, 24_MHz_XTAL, m_floppy_mode); + m_fdc->intrq_wr_callback().set(FUNC(fdc37c665gt_device::irq_floppy_w)); + + // parallel port + PC_LPT(config, m_lpt); + m_lpt->irq_handler().set(FUNC(fdc37c665gt_device::irq_parallel_w)); + + // serial ports + NS16550(config, m_serial[0], clock() / 13); + m_serial[0]->out_int_callback().set(FUNC(fdc37c665gt_device::irq_serial1_w)); + m_serial[0]->out_tx_callback().set(FUNC(fdc37c665gt_device::txd_serial1_w)); + m_serial[0]->out_dtr_callback().set(FUNC(fdc37c665gt_device::dtr_serial1_w)); + m_serial[0]->out_rts_callback().set(FUNC(fdc37c665gt_device::rts_serial1_w)); + + NS16550(config, m_serial[1], clock() / 13); + m_serial[1]->out_int_callback().set(FUNC(fdc37c665gt_device::irq_serial2_w)); + m_serial[1]->out_tx_callback().set(FUNC(fdc37c665gt_device::txd_serial2_w)); + m_serial[1]->out_dtr_callback().set(FUNC(fdc37c665gt_device::dtr_serial2_w)); + m_serial[1]->out_rts_callback().set(FUNC(fdc37c665gt_device::rts_serial2_w)); +} + +uint8_t fdc37c665gt_device::read(offs_t offset) +{ + // TODO: IDE not implemented + + // Parallel port + if (offset >= device_addresses[LogicalDevice::Parallel] && offset <= device_addresses[LogicalDevice::Parallel] + 2) { + if (!enabled_logical[LogicalDevice::Parallel]) { + return 0; + } + + return m_lpt->read(offset - device_addresses[LogicalDevice::Parallel]); } - else - { - printf("fdc37c665gt_device::read %04x %02x\n", offset, data); + + // Serial 1 + if (offset >= com_addresses[device_addresses[LogicalDevice::Serial1]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial1]] + 7) { + if (!enabled_logical[LogicalDevice::Serial1]) { + return 0; + } + + return m_serial[0]->ins8250_r(offset - com_addresses[device_addresses[LogicalDevice::Serial1]]); } - return data; + + // Serial 2 + if (offset >= com_addresses[device_addresses[LogicalDevice::Serial2]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial2]] + 7) { + if (!enabled_logical[LogicalDevice::Serial2]) { + return 0; + } + + return m_serial[1]->ins8250_r(offset - com_addresses[device_addresses[LogicalDevice::Serial2]]); + } + + // FDC, +6 is used by IDE + if ((offset >= device_addresses[LogicalDevice::FDC] && offset <= device_addresses[LogicalDevice::FDC] + 5) + || offset == device_addresses[LogicalDevice::FDC] + 7) { + if (!enabled_logical[LogicalDevice::FDC]) { + return 0; + } + + switch (offset - device_addresses[LogicalDevice::FDC]) { + case 0: return m_fdc->sra_r(); + case 1: return m_fdc->srb_r(); + case 2: return m_fdc->dor_r(); + case 3: return m_fdc->tdr_r(); + case 4: return m_fdc->msr_r(); + case 5: return m_fdc->fifo_r(); + case 7: return m_fdc->dir_r(); + } + } + + return 0; } -WRITE8_MEMBER(fdc37c665gt_device::write) +void fdc37c665gt_device::write(offs_t offset, uint8_t data) { - if ((offset & 0x3f8) == 0x3f8) - { - m_uart1->ins8250_w(offset & 7, data); + // TODO: IDE not implemented + + // Parallel port + if (offset >= device_addresses[LogicalDevice::Parallel] && offset <= device_addresses[LogicalDevice::Parallel] + 2) { + if (!enabled_logical[LogicalDevice::Parallel]) { + return; + } + + m_lpt->write(offset - device_addresses[LogicalDevice::Parallel], data); + return; } - else if ((offset & 0x3f8) == 0x2f8) - { - m_uart2->ins8250_w(offset & 7, data); + + // Serial 1 + if (offset >= com_addresses[device_addresses[LogicalDevice::Serial1]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial1]] + 7) { + if (!enabled_logical[LogicalDevice::Serial1]) { + return; + } + + m_serial[0]->ins8250_w(offset - com_addresses[device_addresses[LogicalDevice::Serial1]], data); + return; } - else - { - printf("fdc37c665gt_device::write %04x %02x\n", offset, data); + + // Serial 2 + if (offset >= com_addresses[device_addresses[LogicalDevice::Serial2]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial2]] + 7) { + if (!enabled_logical[LogicalDevice::Serial2]) { + return; + } + + m_serial[1]->ins8250_w(offset - com_addresses[device_addresses[LogicalDevice::Serial2]], data); + return; + } + + // FDC, +6 is used by IDE + if ((offset >= device_addresses[LogicalDevice::FDC] && offset <= device_addresses[LogicalDevice::FDC] + 5) + || offset == device_addresses[LogicalDevice::FDC] + 7) { + auto fdc_offset = offset - device_addresses[LogicalDevice::FDC]; + + if ((!enabled_logical[LogicalDevice::FDC] && fdc_offset > 1)) { + return; + } + + switch (fdc_offset) { + case 0: // FDC37C665GT Configuration + if (mode == OperatingMode::Run) { + if (data != 0x55) { + config_key_step = 0; + return; + } + + config_key_step++; + if (config_key_step > 1) { + config_key_step = 0; + mode = OperatingMode::Configuration; + } + } else { + if (data == 0xaa) { + mode = OperatingMode::Run; + return; + } + + config_index = data; + } + return; + + case 1: // FDC37C665GT Configuration + if (mode == OperatingMode::Run) { + config_key_step = 0; + return; + } + + write_configuration_register(config_index, data & 0xff); + return; + + case 2: m_fdc->dor_w(data); return; + case 3: m_fdc->tdr_w(data); return; + case 4: m_fdc->dsr_w(data); return; + case 5: m_fdc->fifo_w(data); return; + case 7: m_fdc->ccr_w(data); return; + } } } -void fdc37c665gt_device::device_start() +void fdc37c665gt_device::write_configuration_register(int index, int data) +{ + if (BIT(configuration_registers[1], 7) == 0) { + // Bit 7 of CR1 is LOCK CRx + // When this is set to 0, it can only be set back to 1 by a hard reset or power-up reset + LOGCONFIG("IGNORED configuration register cr[%02x] = %02x\n", index, data); + return; + } + + configuration_registers[index] = data; + LOGCONFIG("Modified configuration register cr[%02x] = %02x\n", index, data); + + if (index == 0) { + enabled_logical[LogicalDevice::IDE] = BIT(configuration_registers[index], 1); + enabled_logical[LogicalDevice::FDC] = BIT(configuration_registers[index], 3) && BIT(configuration_registers[index], 4); + } else if (index == 1) { + enabled_logical[LogicalDevice::Parallel] = BIT(configuration_registers[index], 2) && BIT(configuration_registers[index], 3); + + auto lpt_port = BIT(configuration_registers[index], 0, 2); + if (lpt_port == 0) { + enabled_logical[LogicalDevice::Parallel] = false; // Disabled + } else if (lpt_port == 1) { + device_addresses[LogicalDevice::Parallel] = 0x3bc; + } else if (lpt_port == 2) { + device_addresses[LogicalDevice::Parallel] = 0x378; + } else if (lpt_port == 3) { + device_addresses[LogicalDevice::Parallel] = 0x278; // Default + } + + auto com34 = BIT(configuration_registers[index], 5, 2); + if (com34 == 0) { + com_addresses[2] = 0x338; + com_addresses[3] = 0x238; + } else if (com34 == 1) { + com_addresses[2] = 0x3e8; + com_addresses[3] = 0x2e8; + } else if (com34 == 2) { + com_addresses[2] = 0x2e8; + com_addresses[3] = 0x2e0; + } else if (com34 == 3) { + com_addresses[2] = 0x220; + com_addresses[3] = 0x228; + } + } else if (index == 2) { + enabled_logical[LogicalDevice::Serial1] = BIT(configuration_registers[index], 2) && BIT(configuration_registers[index], 3); + device_addresses[LogicalDevice::Serial1] = BIT(configuration_registers[index], 0, 2); + + enabled_logical[LogicalDevice::Serial2] = BIT(configuration_registers[index], 6) && BIT(configuration_registers[index], 7); + device_addresses[LogicalDevice::Serial2] = BIT(configuration_registers[index], 4, 2); + } else if (index == 3) { + auto floppy_mode = BIT(configuration_registers[index], 5, 2); + + // 2 is reserved/unused + if (floppy_mode == 3) { + m_floppy_mode = upd765_family_device::mode_t::AT; + } else if (floppy_mode == 1) { + m_floppy_mode = upd765_family_device::mode_t::PS2; + } else if (floppy_mode == 0) { + m_floppy_mode = upd765_family_device::mode_t::M30; + } + + m_fdc->set_mode(m_floppy_mode); + } else if (index == 4) { + // Set clock speeds for MIDI modes (clock divisor becomes 12 instead of 13) + m_serial[0]->set_unscaled_clock(clock() / (13 - BIT(configuration_registers[4], 4))); + m_serial[1]->set_unscaled_clock(clock() / (13 - BIT(configuration_registers[5], 5))); + } else if (index == 5) { + auto fdc_port = BIT(configuration_registers[index], 0); + if (fdc_port == 0) { + device_addresses[LogicalDevice::FDC] = 0x3f0; + } else if (fdc_port == 1) { + device_addresses[LogicalDevice::FDC] = 0x370; + } + } +} + +void fdc37c665gt_device::irq_floppy_w(int state) { + if (!enabled_logical[LogicalDevice::FDC]) { + return; + } + + m_fintr_callback(state); } -void fdc37c665gt_device::device_add_mconfig(machine_config &config) +void fdc37c665gt_device::irq_parallel_w(int state) { - NS16550(config, m_uart1, XTAL(24'000'000)/13); - NS16550(config, m_uart2, XTAL(24'000'000)/13); + if (!enabled_logical[LogicalDevice::Parallel]) { + return; + } + + m_pintr1_callback(state); } -DEFINE_DEVICE_TYPE(FDC37C665GT, fdc37c665gt_device, "fdc37c665gt", "FDC37C665GT") +void fdc37c665gt_device::irq_serial1_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial1]) { + return; + } + + m_irq4_callback(state); +} + +void fdc37c665gt_device::txd_serial1_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial1]) { + return; + } + + m_txd1_callback(state); +} + +void fdc37c665gt_device::dtr_serial1_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial1]) { + return; + } + + m_ndtr1_callback(state); +} + +void fdc37c665gt_device::rts_serial1_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial1]) { + return; + } + + m_nrts1_callback(state); +} + +void fdc37c665gt_device::irq_serial2_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial2]) { + return; + } + + m_irq3_callback(state); +} + +void fdc37c665gt_device::txd_serial2_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial2]) { + return; + } + + m_txd2_callback(state); +} + +void fdc37c665gt_device::dtr_serial2_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial2]) { + return; + } + + m_ndtr2_callback(state); +} + +void fdc37c665gt_device::rts_serial2_w(int state) +{ + if (!enabled_logical[LogicalDevice::Serial2]) { + return; + } + + m_nrts2_callback(state); +} + +void fdc37c665gt_device::rxd1_w(int state) +{ + m_serial[0]->rx_w(state); +} + +void fdc37c665gt_device::ndcd1_w(int state) +{ + m_serial[0]->dcd_w(state); +} + +void fdc37c665gt_device::ndsr1_w(int state) +{ + m_serial[0]->dsr_w(state); +} + +void fdc37c665gt_device::nri1_w(int state) +{ + m_serial[0]->ri_w(state); +} + +void fdc37c665gt_device::ncts1_w(int state) +{ + m_serial[0]->cts_w(state); +} + +void fdc37c665gt_device::rxd2_w(int state) +{ + m_serial[1]->rx_w(state); +} + +void fdc37c665gt_device::ndcd2_w(int state) +{ + m_serial[1]->dcd_w(state); +} + +void fdc37c665gt_device::ndsr2_w(int state) +{ + m_serial[1]->dsr_w(state); +} + +void fdc37c665gt_device::nri2_w(int state) +{ + m_serial[1]->ri_w(state); +} + +void fdc37c665gt_device::ncts2_w(int state) +{ + m_serial[1]->cts_w(state); +} |