diff options
Diffstat (limited to 'src/devices/machine/it8705f.cpp')
-rw-r--r-- | src/devices/machine/it8705f.cpp | 593 |
1 files changed, 593 insertions, 0 deletions
diff --git a/src/devices/machine/it8705f.cpp b/src/devices/machine/it8705f.cpp new file mode 100644 index 00000000000..b9dbf3b7054 --- /dev/null +++ b/src/devices/machine/it8705f.cpp @@ -0,0 +1,593 @@ +// license:BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + +Winbond IT8705F LPC Super I/O + +TODO: +- Move stuff from sis950_lpc; +- shutms11 fails detecting FDC; + +**************************************************************************************************/ + +#include "emu.h" +#include "it8705f.h" + +#include "formats/naslite_dsk.h" + +#include <algorithm> + +#define VERBOSE (LOG_GENERAL) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + + +DEFINE_DEVICE_TYPE(IT8705F, it8705f_device, "it8705f", "ITE IT8705F LPC Super I/O") + +it8705f_device::it8705f_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, IT8705F, tag, owner, clock) + , device_isa16_card_interface(mconfig, *this) + , device_memory_interface(mconfig, *this) + , m_space_config("superio_config_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(it8705f_device::config_map), this)) + , m_pc_fdc(*this, "fdc") + , m_pc_com(*this, "uart%d", 0U) + , m_pc_lpt(*this, "lpta") + , m_logical_view(*this, "logical_view") + , m_irq1_callback(*this) + , m_irq8_callback(*this) + , m_irq9_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_index(0) + , m_logical_index(0) + , m_lock_sequence_index(0) +{ + std::fill(std::begin(m_activate), std::end(m_activate), false); +} + +it8705f_device::~it8705f_device() +{ +} + +void it8705f_device::device_start() +{ + set_isa_device(); + m_isa->set_dma_channel(0, this, true); + m_isa->set_dma_channel(1, this, true); + m_isa->set_dma_channel(2, this, true); + m_isa->set_dma_channel(3, this, true); + remap(AS_IO, 0, 0x400); + +} + +void it8705f_device::device_reset() +{ + m_index = 0; + m_lock_sequence_index = 0; + + m_pc_fdc_irq_line = 6; + m_pc_fdc_drq_line = 2; +// m_pc_fdc_mode = ; + m_pc_fdc_address = 0x03f0; + + m_pc_lpt_address = 0x0378; + m_pc_lpt_irq_line = 7; + m_pc_lpt_drq_line = 4; // disabled +// m_pc_lpt_mode = 0x3f; + + m_pc_fdc->set_rate(500000); +} + +device_memory_interface::space_config_vector it8705f_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(0, &m_space_config) + }; +} + +static void pc_hd_floppies(device_slot_interface &device) +{ + device.option_add("525hd", FLOPPY_525_HD); + device.option_add("35hd", FLOPPY_35_HD); + device.option_add("525dd", FLOPPY_525_DD); + device.option_add("35dd", FLOPPY_35_DD); +} + +void it8705f_device::floppy_formats(format_registration &fr) +{ + fr.add_pc_formats(); + fr.add(FLOPPY_NASLITE_FORMAT); +} + +void it8705f_device::device_add_mconfig(machine_config &config) +{ + // 82077 compatible + N82077AA(config, m_pc_fdc, XTAL(24'000'000), upd765_family_device::mode_t::AT); + m_pc_fdc->intrq_wr_callback().set(FUNC(it8705f_device::irq_floppy_w)); + m_pc_fdc->drq_wr_callback().set(FUNC(it8705f_device::drq_floppy_w)); + FLOPPY_CONNECTOR(config, "fdc:0", pc_hd_floppies, "35hd", it8705f_device::floppy_formats); + FLOPPY_CONNECTOR(config, "fdc:1", pc_hd_floppies, "35hd", it8705f_device::floppy_formats); + + NS16550(config, m_pc_com[0], XTAL(24'000'000) / 13); + m_pc_com[0]->out_int_callback().set(FUNC(it8705f_device::irq_serial1_w)); + m_pc_com[0]->out_tx_callback().set(FUNC(it8705f_device::txd_serial1_w)); + m_pc_com[0]->out_dtr_callback().set(FUNC(it8705f_device::dtr_serial1_w)); + m_pc_com[0]->out_rts_callback().set(FUNC(it8705f_device::rts_serial1_w)); + + NS16550(config, m_pc_com[1], XTAL(24'000'000) / 13); + m_pc_com[1]->out_int_callback().set(FUNC(it8705f_device::irq_serial2_w)); + m_pc_com[1]->out_tx_callback().set(FUNC(it8705f_device::txd_serial2_w)); + m_pc_com[1]->out_dtr_callback().set(FUNC(it8705f_device::dtr_serial2_w)); + m_pc_com[1]->out_rts_callback().set(FUNC(it8705f_device::rts_serial2_w)); + + PC_LPT(config, m_pc_lpt); + m_pc_lpt->irq_handler().set(FUNC(it8705f_device::irq_parallel_w)); + +} + + +void it8705f_device::remap(int space_id, offs_t start, offs_t end) +{ + if (space_id == AS_IO) + { + // TODO: apparently installs two ports, an alias at 0x4e/0x4f + m_isa->install_device(0x002e, 0x002f, read8sm_delegate(*this, FUNC(it8705f_device::read)), write8sm_delegate(*this, FUNC(it8705f_device::write))); + + if (m_activate[0]) + { + m_isa->install_device(m_pc_fdc_address, m_pc_fdc_address + 7, *m_pc_fdc, &n82077aa_device::map); + } + + for (int i = 0; i < 2; i++) + { + if (m_activate[i + 1]) + { + const u16 uart_addr = m_pc_com_address[i]; + m_isa->install_device(uart_addr, uart_addr + 7, read8sm_delegate(*m_pc_com[i], FUNC(ns16450_device::ins8250_r)), write8sm_delegate(*m_pc_com[i], FUNC(ns16450_device::ins8250_w))); + } + } + + // can't map below 0x100 + if (m_activate[3] & 1 && m_pc_lpt_address & 0xf00) + { + m_isa->install_device(m_pc_lpt_address, m_pc_lpt_address + 3, read8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::read)), write8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::write))); + } + } +} + +uint8_t it8705f_device::read(offs_t offset) +{ + if (m_lock_sequence_index != 4) + return 0; + + if (offset == 0) + return m_index; + + return space().read_byte(m_index); +} + +void it8705f_device::write(offs_t offset, u8 data) +{ + if (offset == 0) + { + if (m_lock_sequence_index == 4) + m_index = data; + else + { + // TODO: 0xaa for lock_seq[3] with 0x4e alias + const u8 lock_seq[4] = { 0x87, 0x01, 0x55, 0x55 }; + if (data == lock_seq[m_lock_sequence_index]) + m_lock_sequence_index ++; + else + m_lock_sequence_index = 0; + } + } + else + { + if (m_lock_sequence_index == 4) + space().write_byte(m_index, data); + } +} + +void it8705f_device::config_map(address_map &map) +{ + map(0x02, 0x02).lw8( + NAME([this] (offs_t offset, u8 data) { + if (BIT(data, 1)) + m_lock_sequence_index = 0; + // TODO: bit 0 for global reset + }) + ); + map(0x07, 0x07).lr8(NAME([this] () { return m_logical_index; })).w(FUNC(it8705f_device::logical_device_select_w)); + map(0x20, 0x20).lr8(NAME([] () { return 0x87; })); // device ID + map(0x21, 0x21).lr8(NAME([] () { return 0x05; })); // revision +// map(0x22, 0x22) Configuration Select and Chip Version +// map(0x23, 0x23) Software Suspend +// map(0x24, 0x24) Clock Selection and Flash ROM I/F control +// map(0x25, 0x2a) LDN5 GPIO set multi-function pins +// map(0x2b, 0x2b) LDN4 alternate GPIO set multi-function pins +// map(0x2e, 0x2f) LDNF4 Test Modes + + map(0x30, 0xff).view(m_logical_view); + // FDC + m_logical_view[0](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<0>), FUNC(it8705f_device::activate_w<0>)); + m_logical_view[0](0x60, 0x61).lrw8( + NAME([this] (offs_t offset) { + return (m_pc_fdc_address >> (offset * 8)) & 0xff; + }), + NAME([this] (offs_t offset, u8 data) { + const u8 shift = offset * 8; + m_pc_fdc_address &= 0xff << shift; + m_pc_fdc_address |= data << (shift ^ 8); + m_pc_fdc_address &= ~0xf007; + LOG("LDN0 (FDC): remap %04x ([%d] %02x)\n", m_pc_fdc_address, offset, data); + + remap(AS_IO, 0, 0x400); + }) + ); + m_logical_view[0](0x70, 0x70).lrw8( + NAME([this] () { + return m_pc_fdc_irq_line; + }), + NAME([this] (offs_t offset, u8 data) { + m_pc_fdc_irq_line = data & 0xf; + LOG("LDN0 (FDC): irq routed to %02x\n", m_pc_lpt_irq_line); + }) + ); + m_logical_view[0](0x74, 0x74).lrw8( + NAME([this] () { + return m_pc_lpt_drq_line; + }), + NAME([this] (offs_t offset, u8 data) { + m_pc_fdc_drq_line = data & 0x7; + LOG("LDN0 (FDC): drq %s (%02x)\n", BIT(m_pc_lpt_drq_line, 2) ? "disabled" : "enabled", data); + }) + ); + // TODO: m_logical_view[0](0xf0, 0xf1) FDC config + + // UART1 + m_logical_view[1](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<1>), FUNC(it8705f_device::activate_w<1>)); + m_logical_view[1](0x60, 0x61).rw(FUNC(it8705f_device::uart_address_r<0>), FUNC(it8705f_device::uart_address_w<0>)); + m_logical_view[1](0x70, 0x70).rw(FUNC(it8705f_device::uart_irq_r<0>), FUNC(it8705f_device::uart_irq_w<0>)); + m_logical_view[1](0xf0, 0xf0).rw(FUNC(it8705f_device::uart_config_r<0>), FUNC(it8705f_device::uart_config_w<0>)); + + // UART2 + m_logical_view[2](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<2>), FUNC(it8705f_device::activate_w<2>)); + m_logical_view[2](0x60, 0x61).rw(FUNC(it8705f_device::uart_address_r<1>), FUNC(it8705f_device::uart_address_w<1>)); + m_logical_view[2](0x70, 0x70).rw(FUNC(it8705f_device::uart_irq_r<1>), FUNC(it8705f_device::uart_irq_w<1>)); + m_logical_view[2](0xf0, 0xf0).rw(FUNC(it8705f_device::uart_config_r<1>), FUNC(it8705f_device::uart_config_w<1>)); + + // LPT + m_logical_view[3](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<3>), FUNC(it8705f_device::activate_w<3>)); + m_logical_view[3](0x60, 0x61).lrw8( + NAME([this] (offs_t offset) { + return (m_pc_lpt_address >> (offset * 8)) & 0xff; + }), + NAME([this] (offs_t offset, u8 data) { + const u8 shift = offset * 8; + m_pc_lpt_address &= 0xff << shift; + m_pc_lpt_address |= data << (shift ^ 8); + m_pc_lpt_address &= ~0xf003; + LOG("LDN3 (LPT): remap %04x ([%d] %02x)\n", m_pc_lpt_address, offset, data); + + remap(AS_IO, 0, 0x400); + }) + ); + //m_logical_view[3](0x62, 0x63) secondary base address + //m_logical_view[3](0x64, 0x65) POST data port base address + m_logical_view[3](0x70, 0x70).lrw8( + NAME([this] () { + return m_pc_lpt_irq_line; + }), + NAME([this] (offs_t offset, u8 data) { + m_pc_lpt_irq_line = data & 0xf; + LOG("LDN3 (LPT): irq routed to %02x\n", m_pc_lpt_irq_line); + }) + ); + m_logical_view[3](0x74, 0x74).lrw8( + NAME([this] () { + return m_pc_lpt_drq_line; + }), + NAME([this] (offs_t offset, u8 data) { + m_pc_lpt_drq_line = data & 0x7; + LOG("LDN3 (LPT): drq %s (%02x)\n", BIT(m_pc_lpt_drq_line, 2) ? "disabled" : "enabled", data); + }) + ); + + // Environment controller / HW monitor + m_logical_view[4](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<4>), FUNC(it8705f_device::activate_w<4>)); + m_logical_view[4](0x31, 0xff).unmaprw(); + + // GPIO + m_logical_view[5](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<5>), FUNC(it8705f_device::activate_w<5>)); + m_logical_view[5](0x31, 0xff).unmaprw(); + + // Game port + m_logical_view[6](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<6>), FUNC(it8705f_device::activate_w<6>)); + m_logical_view[6](0x31, 0xff).unmaprw(); + + // Consumer IR + m_logical_view[7](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<7>), FUNC(it8705f_device::activate_w<7>)); + m_logical_view[7](0x31, 0xff).unmaprw(); + + // MIDI port + m_logical_view[8](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<8>), FUNC(it8705f_device::activate_w<8>)); + m_logical_view[8](0x31, 0xff).unmaprw(); +} + +/* + * Global register space + */ + +void it8705f_device::logical_device_select_w(offs_t offset, u8 data) +{ + m_logical_index = data; + if (m_logical_index <= 0x8) + m_logical_view.select(m_logical_index); + else + LOG("Attempt to select an unmapped device with %02x\n", data); +} + +template <unsigned N> u8 it8705f_device::activate_r(offs_t offset) +{ + return m_activate[N]; +} + +template <unsigned N> void it8705f_device::activate_w(offs_t offset, u8 data) +{ + m_activate[N] = data & 1; + LOG("LDN%d Device %s\n", N, data & 1 ? "enabled" : "disabled"); + remap(AS_IO, 0, 0x400); +} + +void it8705f_device::request_irq(int irq, int state) +{ + switch (irq) + { + case 1: + m_irq1_callback(state); + break; + 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 8: + m_irq8_callback(state); + break; + case 9: + m_irq9_callback(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; + } +} + +void it8705f_device::request_dma(int dreq, int state) +{ + switch (dreq) + { + case 0: + m_isa->drq0_w(state); + break; + case 1: + m_isa->drq1_w(state); + break; + case 2: + m_isa->drq2_w(state); + break; + case 3: + m_isa->drq3_w(state); + break; + } +} + +/* + * Device #0 (FDC) + */ + +void it8705f_device::irq_floppy_w(int state) +{ + if (!m_activate[0]) + return; + request_irq(m_pc_fdc_irq_line, state ? ASSERT_LINE : CLEAR_LINE); +} + +void it8705f_device::drq_floppy_w(int state) +{ + if (!m_activate[0]) + return; + request_dma(m_pc_fdc_drq_line, state ? ASSERT_LINE : CLEAR_LINE); +} + +/* + * Device #1/#2 (UART) + */ + +template <unsigned N> u8 it8705f_device::uart_address_r(offs_t offset) +{ + return (m_pc_com_address[N] >> (offset * 8)) & 0xff; +} + +template <unsigned N> void it8705f_device::uart_address_w(offs_t offset, u8 data) +{ + const u8 shift = offset * 8; + m_pc_com_address[N] &= 0xff << shift; + m_pc_com_address[N] |= data << (shift ^ 8); + m_pc_com_address[N] &= ~0xf007; + LOG("LDN%d (COM%d): remap %04x ([%d] %02x)\n", N, N + 1, m_pc_com_address[N], offset, data); + + remap(AS_IO, 0, 0x400); +} + +template <unsigned N> u8 it8705f_device::uart_irq_r(offs_t offset) +{ + return m_pc_com_irq_line[N]; +} + +template <unsigned N> void it8705f_device::uart_irq_w(offs_t offset, u8 data) +{ + m_pc_com_irq_line[N] = data & 0xf; + LOG("LDN%d (UART): irq routed to %02x\n", N, m_pc_com_irq_line[N]); +} + +template <unsigned N> u8 it8705f_device::uart_config_r(offs_t offset) +{ + return m_pc_com_control[N]; +} + +/* + * ---- -xx- Clock Source + * ---- -00- 24 MHz/13 + * ---- -??- <reserved> + * ---- ---x IRQ sharing enable + */ +template <unsigned N> void it8705f_device::uart_config_w(offs_t offset, u8 data) +{ + m_pc_com_control[N] = data; + LOG("LDN%d (UART): control %02x\n", N, m_pc_com_control[N]); +} + +void it8705f_device::irq_serial1_w(int state) +{ + if (!m_activate[1]) + return; + request_irq(m_pc_com_irq_line[0], state ? ASSERT_LINE : CLEAR_LINE); +} + +void it8705f_device::irq_serial2_w(int state) +{ + if (!m_activate[2]) + return; + request_irq(m_pc_com_irq_line[1], state ? ASSERT_LINE : CLEAR_LINE); +} + +void it8705f_device::txd_serial1_w(int state) +{ + if (!m_activate[1]) + return; + m_txd1_callback(state); +} + +void it8705f_device::txd_serial2_w(int state) +{ + if (!m_activate[2]) + return; + m_txd2_callback(state); +} + +void it8705f_device::dtr_serial1_w(int state) +{ + if (!m_activate[1]) + return; + m_ndtr1_callback(state); +} + +void it8705f_device::dtr_serial2_w(int state) +{ + if (!m_activate[2]) + return; + m_ndtr2_callback(state); +} + +void it8705f_device::rts_serial1_w(int state) +{ + if (!m_activate[1]) + return; + m_nrts1_callback(state); +} + +void it8705f_device::rts_serial2_w(int state) +{ + if (!m_activate[2]) + return; + m_nrts2_callback(state); +} + +void it8705f_device::rxd1_w(int state) +{ + m_pc_com[0]->rx_w(state); +} + +void it8705f_device::ndcd1_w(int state) +{ + m_pc_com[0]->dcd_w(state); +} + +void it8705f_device::ndsr1_w(int state) +{ + m_pc_com[0]->dsr_w(state); +} + +void it8705f_device::nri1_w(int state) +{ + m_pc_com[0]->ri_w(state); +} + +void it8705f_device::ncts1_w(int state) +{ + m_pc_com[0]->cts_w(state); +} + +void it8705f_device::rxd2_w(int state) +{ + m_pc_com[1]->rx_w(state); +} + +void it8705f_device::ndcd2_w(int state) +{ + m_pc_com[1]->dcd_w(state); +} + +void it8705f_device::ndsr2_w(int state) +{ + m_pc_com[1]->dsr_w(state); +} + +void it8705f_device::nri2_w(int state) +{ + m_pc_com[1]->ri_w(state); +} + +void it8705f_device::ncts2_w(int state) +{ + m_pc_com[1]->cts_w(state); +} + +/* + * Device #3 (Parallel) + */ + +void it8705f_device::irq_parallel_w(int state) +{ + if (m_activate[3] == false) + return; + request_irq(m_pc_lpt_irq_line, state ? ASSERT_LINE : CLEAR_LINE); +} |