summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/sgi/ioc2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/sgi/ioc2.cpp')
-rw-r--r--src/mame/sgi/ioc2.cpp760
1 files changed, 760 insertions, 0 deletions
diff --git a/src/mame/sgi/ioc2.cpp b/src/mame/sgi/ioc2.cpp
new file mode 100644
index 00000000000..4f24eb5ff3d
--- /dev/null
+++ b/src/mame/sgi/ioc2.cpp
@@ -0,0 +1,760 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/**********************************************************************
+
+ SGI IOC2 I/O Controller emulation
+
+**********************************************************************/
+
+#include "emu.h"
+#include "bus/rs232/rs232.h"
+#include "machine/input_merger.h"
+#include "ioc2.h"
+
+#define LOG_PI1 (1U << 1)
+#define LOG_SERIAL (1U << 2)
+#define LOG_MOUSEKBD (1U << 3)
+#define LOG_PANEL (1U << 4)
+#define LOG_SYSID (1U << 5)
+#define LOG_READ (1U << 6)
+#define LOG_DMA_SEL (1U << 7)
+#define LOG_RESET (1U << 8)
+#define LOG_WRITE (1U << 9)
+#define LOG_INT3 (1U << 10)
+#define LOG_PIT (1U << 11)
+#define LOG_IRQS (1U << 12)
+#define LOG_ALL (LOG_PI1 | LOG_SERIAL | LOG_MOUSEKBD | LOG_PANEL | LOG_SYSID | LOG_READ | LOG_DMA_SEL | LOG_RESET | LOG_WRITE | LOG_INT3 | LOG_PIT | LOG_IRQS)
+#define LOG_DEFAULT (LOG_ALL & ~(LOG_SYSID))
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+/*static*/ char const *const ioc2_device::SCC_TAG = "scc";
+/*static*/ char const *const ioc2_device::PI1_TAG = "pi1";
+/*static*/ char const *const ioc2_device::KBDC_TAG = "kbdc";
+/*static*/ char const *const ioc2_device::PIT_TAG = "pit";
+/*static*/ char const *const ioc2_device::RS232A_TAG = "rs232a";
+/*static*/ char const *const ioc2_device::RS232B_TAG = "rs232b";
+
+/*static*/ const XTAL ioc2_device::SCC_PCLK = 10_MHz_XTAL;
+/*static*/ const XTAL ioc2_device::SCC_RXA_CLK = 3.6864_MHz_XTAL; // Needs verification
+/*static*/ const XTAL ioc2_device::SCC_TXA_CLK = XTAL(0);
+/*static*/ const XTAL ioc2_device::SCC_RXB_CLK = 3.6864_MHz_XTAL; // Needs verification
+/*static*/ const XTAL ioc2_device::SCC_TXB_CLK = XTAL(0);
+
+DEFINE_DEVICE_TYPE(SGI_IOC2_GUINNESS, ioc2_guinness_device, "ioc2g", "SGI IOC2 (Guinness)")
+DEFINE_DEVICE_TYPE(SGI_IOC2_FULL_HOUSE, ioc2_full_house_device, "ioc2f", "SGI IOC2 (Full House)")
+
+ioc2_guinness_device::ioc2_guinness_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ioc2_device(mconfig, SGI_IOC2_GUINNESS, tag, owner, clock)
+{
+}
+
+ioc2_full_house_device::ioc2_full_house_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ioc2_device(mconfig, SGI_IOC2_FULL_HOUSE, tag, owner, clock)
+{
+}
+
+static INPUT_PORTS_START( front_panel )
+ PORT_START("panel_buttons")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Power") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(ioc2_device::power_button), 0)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Volume Down") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(ioc2_device::volume_down), 0)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Volume Up") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(ioc2_device::volume_up), 0)
+INPUT_PORTS_END
+
+ioport_constructor ioc2_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(front_panel);
+}
+
+void ioc2_device::device_add_mconfig(machine_config &config)
+{
+ SCC85230(config, m_scc, SCC_PCLK);
+ m_scc->configure_channels(SCC_RXA_CLK.value(), SCC_TXA_CLK.value(), SCC_RXB_CLK.value(), SCC_TXB_CLK.value());
+ m_scc->out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd));
+ m_scc->out_dtra_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_dtr));
+ m_scc->out_rtsa_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_rts));
+ m_scc->out_txdb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_txd));
+ m_scc->out_dtrb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_dtr));
+ m_scc->out_rtsb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_rts));
+ m_scc->out_int_callback().set(FUNC(ioc2_device::duart_int_w));
+
+ rs232_port_device &rs232a(RS232_PORT(config, RS232A_TAG, default_rs232_devices, nullptr));
+ rs232a.cts_handler().set(m_scc, FUNC(scc85230_device::ctsa_w));
+ rs232a.dcd_handler().set(m_scc, FUNC(scc85230_device::dcda_w));
+ rs232a.rxd_handler().set(m_scc, FUNC(scc85230_device::rxa_w));
+
+ rs232_port_device &rs232b(RS232_PORT(config, RS232B_TAG, default_rs232_devices, nullptr));
+ rs232b.cts_handler().set(m_scc, FUNC(scc85230_device::ctsb_w));
+ rs232b.dcd_handler().set(m_scc, FUNC(scc85230_device::dcdb_w));
+ rs232b.rxd_handler().set(m_scc, FUNC(scc85230_device::rxb_w));
+
+ PC_LPT(config, m_pi1);
+
+ // keyboard connector
+ pc_kbdc_device &kbd_con(PC_KBDC(config, "kbd", pc_at_keyboards, STR_KBD_MICROSOFT_NATURAL));
+ kbd_con.out_clock_cb().set(m_kbdc, FUNC(ps2_keyboard_controller_device::kbd_clk_w));
+ kbd_con.out_data_cb().set(m_kbdc, FUNC(ps2_keyboard_controller_device::kbd_data_w));
+
+ // auxiliary connector
+ pc_kbdc_device &aux_con(PC_KBDC(config, "aux", ps2_mice, STR_HLE_PS2_MOUSE));
+ aux_con.out_clock_cb().set(m_kbdc, FUNC(ps2_keyboard_controller_device::aux_clk_w));
+ aux_con.out_data_cb().set(m_kbdc, FUNC(ps2_keyboard_controller_device::aux_data_w));
+
+ // keyboard controller
+ PS2_KEYBOARD_CONTROLLER(config, m_kbdc, 12_MHz_XTAL);
+ m_kbdc->kbd_clk().set(kbd_con, FUNC(pc_kbdc_device::clock_write_from_mb));
+ m_kbdc->kbd_data().set(kbd_con, FUNC(pc_kbdc_device::data_write_from_mb));
+ m_kbdc->aux_clk().set(aux_con, FUNC(pc_kbdc_device::clock_write_from_mb));
+ m_kbdc->aux_data().set(aux_con, FUNC(pc_kbdc_device::data_write_from_mb));
+
+ input_merger_device &kbdc_irq(INPUT_MERGER_ANY_HIGH(config, "kbdc_irq"));
+ kbdc_irq.output_handler().set(FUNC(ioc2_device::kbdc_int_w));
+ m_kbdc->kbd_irq().set(kbdc_irq, FUNC(input_merger_device::in_w<0>));
+ m_kbdc->aux_irq().set(kbdc_irq, FUNC(input_merger_device::in_w<1>));
+
+ PIT8254(config, m_pit);
+ m_pit->set_clk<0>(0);
+ m_pit->set_clk<1>(0);
+ m_pit->set_clk<2>(1000000);
+ m_pit->out_handler<0>().set(FUNC(ioc2_device::timer0_int));
+ m_pit->out_handler<1>().set(FUNC(ioc2_device::timer1_int));
+ m_pit->out_handler<2>().set(FUNC(ioc2_device::pit_clock2_out));
+}
+
+
+ioc2_device::ioc2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_maincpu(*this, finder_base::DUMMY_TAG)
+ , m_scc(*this, SCC_TAG)
+ , m_pi1(*this, PI1_TAG)
+ , m_kbdc(*this, KBDC_TAG)
+ , m_pit(*this, PIT_TAG)
+ , m_gen_ctrl_select_reg(0)
+ , m_gen_ctrl_reg(0)
+ , m_front_panel_reg(0)
+ , m_read_reg(0)
+ , m_dma_sel(0)
+ , m_reset_reg(0)
+ , m_write_reg(0)
+ , m_int3_map_status_reg(0)
+ , m_int3_map_pol_reg(0)
+ , m_int3_err_status_reg(0)
+ , m_par_read_cnt(0)
+ , m_par_cntl(0)
+{
+}
+
+void ioc2_device::device_start()
+{
+ save_item(NAME(m_par_read_cnt));
+ save_item(NAME(m_par_cntl));
+
+ save_item(NAME(m_gen_ctrl_select_reg));
+ save_item(NAME(m_gen_ctrl_reg));
+ save_item(NAME(m_front_panel_reg));
+
+ save_item(NAME(m_read_reg));
+ save_item(NAME(m_dma_sel));
+ save_item(NAME(m_reset_reg));
+ save_item(NAME(m_write_reg));
+
+ save_item(NAME(m_int3_local_status_reg));
+ save_item(NAME(m_int3_local_mask_reg));
+ save_item(NAME(m_int3_map_status_reg));
+ save_item(NAME(m_int3_map_mask_reg));
+ save_item(NAME(m_int3_map_pol_reg));
+ save_item(NAME(m_int3_err_status_reg));
+}
+
+void ioc2_device::device_reset()
+{
+ m_par_read_cnt = 0;
+ m_par_cntl = 0;
+
+ m_gen_ctrl_select_reg = 0;
+ m_gen_ctrl_reg = 0;
+ m_front_panel_reg = FRONT_PANEL_VOL_UP_HOLD | FRONT_PANEL_VOL_DOWN_HOLD | FRONT_PANEL_POWER_STATE;
+
+ m_read_reg = 0;
+ m_dma_sel = 0;
+ m_reset_reg = 0;
+ m_write_reg = 0;
+
+ memset(m_int3_local_status_reg, 0, sizeof(uint8_t) * 2);
+ memset(m_int3_local_mask_reg, 0, sizeof(uint8_t) * 2);
+ m_int3_map_status_reg = 0;
+ memset(m_int3_map_mask_reg, 0, sizeof(uint8_t) * 2);
+ m_int3_map_pol_reg = 0;
+ m_int3_err_status_reg = 0;
+}
+
+void ioc2_device::raise_local_irq(int channel, uint8_t mask)
+{
+ const uint8_t old = m_int3_local_status_reg[channel];
+ m_int3_local_status_reg[channel] |= mask;
+ LOGMASKED(LOG_IRQS, "Raising Local%d interrupt mask %02x, interrupt status was %02x, now %02x, %sing interrupt\n", channel, mask, old,
+ m_int3_local_status_reg[channel], (m_int3_local_mask_reg[channel] & m_int3_local_status_reg[channel]) ? "rais" : "lower");
+ m_maincpu->set_input_line(channel, (m_int3_local_mask_reg[channel] & m_int3_local_status_reg[channel]) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void ioc2_device::lower_local_irq(int channel, uint8_t mask)
+{
+ const uint8_t old = m_int3_local_status_reg[channel];
+ m_int3_local_status_reg[channel] &= ~mask;
+ LOGMASKED(LOG_IRQS, "Lowering Local%d interrupt mask %02x, interrupt status was %02x, now %02x, %sing interrupt\n", channel, mask, old,
+ m_int3_local_status_reg[channel], (m_int3_local_mask_reg[channel] & m_int3_local_status_reg[channel]) ? "rais" : "lower");
+ m_maincpu->set_input_line(channel, (m_int3_local_mask_reg[channel] & m_int3_local_status_reg[channel]) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void ioc2_device::timer0_int(int state)
+{
+ if (state)
+ {
+ LOGMASKED(LOG_IRQS, "Raising IRQ line 2\n");
+ m_maincpu->set_input_line(2, ASSERT_LINE);
+ }
+}
+
+void ioc2_device::timer1_int(int state)
+{
+ if (state)
+ {
+ LOGMASKED(LOG_IRQS, "Raising IRQ line 3\n");
+ m_maincpu->set_input_line(3, ASSERT_LINE);
+ }
+}
+
+void ioc2_device::pit_clock2_out(int state)
+{
+ m_pit->write_clk0(state);
+ m_pit->write_clk1(state);
+}
+
+void ioc2_device::kbdc_int_w(int state)
+{
+ set_mappable_int(0x10, state);
+}
+
+void ioc2_device::duart_int_w(int state)
+{
+ set_mappable_int(0x20, state);
+}
+
+void ioc2_device::set_mappable_int(uint8_t mask, bool state)
+{
+ const uint8_t old = m_int3_map_status_reg;
+ const uint8_t old0 = m_int3_map_mask_reg[0] & old;
+ const uint8_t old1 = m_int3_map_mask_reg[1] & old;
+
+ if (state)
+ m_int3_map_status_reg |= mask;
+ else
+ m_int3_map_status_reg &= ~mask;
+
+ const uint8_t new0 = m_int3_map_mask_reg[0] & m_int3_map_status_reg;
+ if (old0 ^ new0)
+ {
+ check_mappable_interrupt(0);
+ }
+
+ const uint8_t new1 = m_int3_map_mask_reg[1] & m_int3_map_status_reg;
+ if (old1 ^ new1)
+ {
+ check_mappable_interrupt(1);
+ }
+}
+
+void ioc2_device::check_mappable_interrupt(int channel)
+{
+ if (channel == 0)
+ {
+ if (m_int3_map_mask_reg[channel] & m_int3_map_status_reg)
+ raise_local_irq(channel, INT3_LOCAL0_MAPPABLE0);
+ else
+ lower_local_irq(channel, INT3_LOCAL0_MAPPABLE0);
+ }
+ else
+ {
+ if (m_int3_map_mask_reg[channel] & m_int3_map_status_reg)
+ raise_local_irq(channel, INT3_LOCAL1_MAPPABLE1);
+ else
+ lower_local_irq(channel, INT3_LOCAL1_MAPPABLE1);
+ }
+}
+
+u8 ioc2_device::pi1_dma_ctrl_r()
+{
+ LOGMASKED(LOG_PI1, "%s: Read PI1 DMA Control Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+void ioc2_device::pi1_dma_ctrl_w(u8 data)
+{
+ LOGMASKED(LOG_PI1, "%s: Write PI1 DMA Control Register: %02x\n", machine().describe_context(), data);
+}
+
+u8 ioc2_device::pi1_int_status_r()
+{
+ LOGMASKED(LOG_PI1, "%s: Read PI1 Interrupt Status Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+void ioc2_device::pi1_int_status_w(u8 data)
+{
+ LOGMASKED(LOG_PI1, "%s: Write PI1 Interrupt Status Register: %02x\n", machine().describe_context(), data);
+}
+
+u8 ioc2_device::pi1_int_mask_r()
+{
+ LOGMASKED(LOG_PI1, "%s: Read PI1 Interrupt Mask Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+void ioc2_device::pi1_int_mask_w(u8 data)
+{
+ LOGMASKED(LOG_PI1, "%s: Write PI1 Interrupt Mask Register: %02x\n", machine().describe_context(), data);
+}
+
+u8 ioc2_device::pi1_timer1_r()
+{
+ LOGMASKED(LOG_PI1, "%s: Read PI1 Timer1 Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+u8 ioc2_device::pi1_timer2_r()
+{
+ LOGMASKED(LOG_PI1, "%s: Read PI1 Timer2 Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+u8 ioc2_device::pi1_timer3_r()
+{
+ LOGMASKED(LOG_PI1, "%s: Read PI1 Timer3 Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+u8 ioc2_device::pi1_timer4_r()
+{
+ LOGMASKED(LOG_PI1, "%s: Read PI1 Timer4 Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+void ioc2_device::pi1_timer1_w(u8 data)
+{
+ LOGMASKED(LOG_PI1, "%s: Write PI1 Timer1 Register: %02x\n", machine().describe_context(), data);
+}
+
+void ioc2_device::pi1_timer2_w(u8 data)
+{
+ LOGMASKED(LOG_PI1, "%s: Write PI1 Timer2 Register: %02x\n", machine().describe_context(), data);
+}
+
+void ioc2_device::pi1_timer3_w(u8 data)
+{
+ LOGMASKED(LOG_PI1, "%s: Write PI1 Timer3 Register: %02x\n", machine().describe_context(), data);
+}
+
+void ioc2_device::pi1_timer4_w(u8 data)
+{
+ LOGMASKED(LOG_PI1, "%s: Write PI1 Timer4 Register: %02x\n", machine().describe_context(), data);
+}
+
+u8 ioc2_device::gc_select_r()
+{
+ LOGMASKED(LOG_READ, "%s: Read GC Select Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+void ioc2_device::gc_select_w(u8 data)
+{
+ LOGMASKED(LOG_WRITE, "%s: Write GC Select Register: %02x\n", machine().describe_context(), data);
+}
+
+u8 ioc2_device::gen_cntl_r()
+{
+ LOGMASKED(LOG_READ, "%s: Read General Control Register: 00\n", machine().describe_context());
+ return 0;
+}
+
+void ioc2_device::gen_cntl_w(u8 data)
+{
+ LOGMASKED(LOG_WRITE, "%s: Write General Control Register: %02x\n", machine().describe_context(), data);
+}
+
+u8 ioc2_device::front_panel_r()
+{
+ LOGMASKED(LOG_PANEL, "%s: Read Front Panel Register: %02x\n", machine().describe_context(), m_front_panel_reg);
+ return m_front_panel_reg;
+}
+
+void ioc2_device::front_panel_w(u8 data)
+{
+ LOGMASKED(LOG_PANEL, "%s: Write Front Panel Register: %02x\n", machine().describe_context(), data);
+ m_front_panel_reg &= ~(data & (FRONT_PANEL_VOL_UP_INT | FRONT_PANEL_VOL_DOWN_INT | FRONT_PANEL_POWER_BUTTON_INT));
+ if (!(m_front_panel_reg & FRONT_PANEL_INT_MASK))
+ lower_local_irq(1, INT3_LOCAL1_PANEL);
+}
+
+u8 ioc2_device::system_id_r()
+{
+ const uint8_t data = get_system_id();
+ LOGMASKED(LOG_SYSID, "%s: Read System ID Register: %02x\n", machine().describe_context(), data);
+ return data;
+}
+
+u8 ioc2_device::read_r()
+{
+ LOGMASKED(LOG_READ, "%s: Read Read Register: %02x\n", machine().describe_context(), m_read_reg);
+ return m_read_reg;
+}
+
+u8 ioc2_device::dma_sel_r()
+{
+ // Bits 2-0 not quite understood, seem to be copy/paste error in SGI's own documents:
+ //
+ // 2 RW Parallel Port DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [this makes sense. -ed.]
+ // 1 RW ISDN Channel B DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [is this a copy/paste error? perhaps "Parallel Port" should be "ISDN Channel B"?]
+ // 0 RW [same text as above. Another copy/paste error, maybe? Should be channel A, with the bit selecting DMA channel 0/1 for ISDN channel A, the and the same for ISDN channel B in bit 1?]
+ LOGMASKED(LOG_DMA_SEL, "%s: Read DMA Select Register: %02x\n", machine().describe_context(), m_dma_sel);
+ return m_dma_sel;
+}
+
+void ioc2_device::dma_sel_w(u8 data)
+{
+ // Bits 2-0 not quite understood, seem to be copy/paste error in SGI's own documents:
+ //
+ // 5:4 RW Serial Port Clock Select: 00 selects a 10MHz internal clock (default), 01 selects a 6.67MHz internal clock, and 02 or 03 selects the external clock input.
+ // 2 RW Parallel Port DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [this makes sense. -ed.]
+ // 1 RW ISDN Channel B DMA Select. A high bit selects the Parallel Port DMA channel. 0\h is the default after reset. [is this a copy/paste error? perhaps "Parallel Port" should be "ISDN Channel B"?]
+ // 0 RW [same text as above. Another copy/paste error, maybe? Should be channel A, with the bit selecting DMA channel 0/1 for ISDN channel A, the and the same for ISDN channel B in bit 1?]
+ LOGMASKED(LOG_DMA_SEL, "%s: Write DMA Select Register: %02x\n", machine().describe_context(), data);
+ uint8_t old = m_dma_sel;
+ m_dma_sel = data;
+ uint8_t changed = old ^ m_dma_sel;
+ if (changed & DMA_SEL_CLOCK_SEL_MASK)
+ {
+ if (changed & DMA_SEL_CLOCK_SEL_EXT)
+ {
+ LOGMASKED(LOG_DMA_SEL, "%s: External clock select %sselected\n", machine().describe_context(), (old & DMA_SEL_CLOCK_SEL_EXT) != 0 ? "de" : "");
+ // TODO: verify the external Rx/Tx clock, is it fixed or programmable?
+ }
+ }
+ // TODO: Currently we always assume a 10MHz clock as PCLK
+}
+
+u8 ioc2_device::reset_r()
+{
+ LOGMASKED(LOG_RESET, "%s: Read Reset Register: %02x\n", machine().describe_context(), m_reset_reg);
+ return m_reset_reg;
+}
+
+void ioc2_device::reset_w(u8 data)
+{
+ LOGMASKED(LOG_RESET, "%s: Write Reset Register: %02x\n", machine().describe_context(), data);
+ handle_reset_reg_write(data);
+}
+
+u8 ioc2_device::write_r()
+{
+ // Not yet implemented, some bits unnecessary:
+ //
+ // Bit Oper Description
+ // 7 RW Margin High. Set low for normal +5V operation, high to step supply up to +5.5V. Cleared at reset.
+ // 6 RW Margin Low. Set lowf or normal +5V operation, high to step supply down to +4.5V. Cleared at reset.
+ // 5 RW UART1 PC Mode. Set low to configure Port1 for RS422 Mac mode, high to select RS232 PC mode. Cleared at reset.
+ // 4 RW UART2 PC Mode. Set low to configure Port2 for RS422 Mac mode, high to select RS232 PC mode. Cleared at reset.
+ // 3 RW Ethernet Auto Select (active high). Set low for manual mode, high to have LXT901 automatically select TP or AUI based on link integrity. Cleared at reset.
+ // 2 RW Ethernet Port Select. Set low for TP, high for AUI. This setting is only used when Auto Select is in manual mode. Cleared at reset.
+ // 1 RW Ethernet UTP/STP select. Set low to select 150 ohm termination fro shielded TP (default), set high to select 100 ohm termination for unshielded TP. Cleared at reset.
+ // 0 RW Ethernet Normal Threshold (NTH) select. Set low to select the normal TP squelch threshold (default), high to reduce threshold by 4.5 dB (set low when reset).
+ LOGMASKED(LOG_WRITE, "%s: Read Write Register: %02x\n", machine().describe_context(), m_write_reg);
+ return m_write_reg;
+}
+
+void ioc2_device::write_w(u8 data)
+{
+ LOGMASKED(LOG_WRITE, "%s: Write Write Register: %02x\n", machine().describe_context(), data);
+ m_write_reg = data;
+}
+
+template <int N>
+u8 ioc2_device::local_status_r()
+{
+ LOGMASKED(LOG_INT3, "%s: Read Interrupt Local%d Status Register: %02x\n", machine().describe_context(), N, m_int3_local_status_reg[N]);
+ return m_int3_local_status_reg[N];
+}
+
+template <int N>
+u8 ioc2_device::local_mask_r()
+{
+ LOGMASKED(LOG_INT3, "%s: Read Interrupt Local%d Mask Register: %02x\n", machine().describe_context(), N, m_int3_local_mask_reg[N]);
+ return m_int3_local_mask_reg[N];
+}
+
+template <int N>
+void ioc2_device::local_mask_w(u8 data)
+{
+ LOGMASKED(LOG_INT3, "%s: Write Interrupt Local%d Mask Register: %02x\n", machine().describe_context(), N, data);
+ set_local_int_mask(N, data);
+}
+
+u8 ioc2_device::map_status_r()
+{
+ LOGMASKED(LOG_INT3, "%s: Read Interrupt Map Status Register: %02x\n", machine().describe_context(), m_int3_map_status_reg);
+ return m_int3_map_status_reg;
+}
+
+template <int N>
+u8 ioc2_device::map_mask_r()
+{
+ LOGMASKED(LOG_INT3, "%s: Read Interrupt Map Mask%d Register: %02x\n", machine().describe_context(), N, m_int3_map_mask_reg[N]);
+ return m_int3_map_mask_reg[N];
+}
+
+template <int N>
+void ioc2_device::map_mask_w(u8 data)
+{
+ LOGMASKED(LOG_INT3, "%s: Write Interrupt Map Mask%d Register: %02x\n", machine().describe_context(), N, data);
+ set_map_int_mask(N, data);
+}
+
+u8 ioc2_device::map_pol_r()
+{
+ LOGMASKED(LOG_INT3, "%s: Read Interrupt Map Polarity Register: %02x\n", machine().describe_context(), m_int3_map_pol_reg);
+ return m_int3_map_pol_reg;
+}
+
+void ioc2_device::map_pol_w(u8 data)
+{
+ // TODO: Mappable interrupt polarity select
+ LOGMASKED(LOG_INT3, "%s: Write Interrupt Map Polarity Register: %02x\n", machine().describe_context(), data);
+ m_int3_map_pol_reg = data;
+}
+
+void ioc2_device::timer_int_clear_w(u8 data)
+{
+ LOGMASKED(LOG_INT3, "%s: Write Interrupt Timer Clear Register: %02x\n", machine().describe_context(), data);
+ set_timer_int_clear(data);
+}
+
+u8 ioc2_device::error_status_r()
+{
+ LOGMASKED(LOG_INT3, "%s: Read Interrupt Error Status Register: %02x\n", machine().describe_context(), m_int3_err_status_reg);
+ return m_int3_err_status_reg;
+}
+
+void ioc2_device::base_map(address_map &map)
+{
+ map(0x00, 0x02).rw(m_pi1, FUNC(pc_lpt_device::read), FUNC(pc_lpt_device::write));
+ map(0x03, 0x03).rw(FUNC(ioc2_device::pi1_dma_ctrl_r), FUNC(ioc2_device::pi1_dma_ctrl_w));
+ map(0x04, 0x04).rw(FUNC(ioc2_device::pi1_int_status_r), FUNC(ioc2_device::pi1_int_status_w));
+ map(0x05, 0x05).rw(FUNC(ioc2_device::pi1_int_mask_r), FUNC(ioc2_device::pi1_int_mask_w));
+ map(0x06, 0x06).rw(FUNC(ioc2_device::pi1_timer1_r), FUNC(ioc2_device::pi1_timer1_w));
+ map(0x07, 0x07).rw(FUNC(ioc2_device::pi1_timer2_r), FUNC(ioc2_device::pi1_timer2_w));
+ map(0x08, 0x08).rw(FUNC(ioc2_device::pi1_timer3_r), FUNC(ioc2_device::pi1_timer3_w));
+ map(0x09, 0x09).rw(FUNC(ioc2_device::pi1_timer4_r), FUNC(ioc2_device::pi1_timer4_w));
+ map(0x0c, 0x0f).rw(m_scc, FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w));
+ map(0x10, 0x10).rw(m_kbdc, FUNC(ps2_keyboard_controller_device::data_r), FUNC(ps2_keyboard_controller_device::data_w));
+ map(0x11, 0x11).rw(m_kbdc, FUNC(ps2_keyboard_controller_device::status_r), FUNC(ps2_keyboard_controller_device::command_w));
+ map(0x12, 0x12).rw(FUNC(ioc2_device::gc_select_r), FUNC(ioc2_device::gc_select_w));
+ map(0x13, 0x13).rw(FUNC(ioc2_device::gen_cntl_r), FUNC(ioc2_device::gen_cntl_w));
+ map(0x14, 0x14).rw(FUNC(ioc2_device::front_panel_r), FUNC(ioc2_device::front_panel_w));
+ map(0x16, 0x16).r(FUNC(ioc2_device::system_id_r));
+ map(0x18, 0x18).r(FUNC(ioc2_device::read_r));
+ map(0x1a, 0x1a).rw(FUNC(ioc2_device::dma_sel_r), FUNC(ioc2_device::dma_sel_w));
+ map(0x1c, 0x1c).rw(FUNC(ioc2_device::reset_r), FUNC(ioc2_device::reset_w));
+ map(0x1e, 0x1e).rw(FUNC(ioc2_device::write_r), FUNC(ioc2_device::write_w));
+}
+
+void ioc2_guinness_device::map(address_map &map)
+{
+ base_map(map);
+ map(0x20, 0x20).r(FUNC(ioc2_guinness_device::local_status_r<0>));
+ map(0x21, 0x21).rw(FUNC(ioc2_guinness_device::local_mask_r<0>), FUNC(ioc2_guinness_device::local_mask_w<0>));
+ map(0x22, 0x22).r(FUNC(ioc2_guinness_device::local_status_r<1>));
+ map(0x23, 0x23).rw(FUNC(ioc2_guinness_device::local_mask_r<1>), FUNC(ioc2_guinness_device::local_mask_w<1>));
+ map(0x24, 0x24).r(FUNC(ioc2_guinness_device::map_status_r));
+ map(0x25, 0x25).rw(FUNC(ioc2_guinness_device::map_mask_r<0>), FUNC(ioc2_guinness_device::map_mask_w<0>));
+ map(0x26, 0x26).rw(FUNC(ioc2_guinness_device::map_mask_r<1>), FUNC(ioc2_guinness_device::map_mask_w<1>));
+ map(0x27, 0x27).rw(FUNC(ioc2_guinness_device::map_pol_r), FUNC(ioc2_guinness_device::map_pol_w));
+ map(0x28, 0x28).w(FUNC(ioc2_guinness_device::timer_int_clear_w));
+ map(0x29, 0x29).r(FUNC(ioc2_guinness_device::error_status_r));
+ map(0x2c, 0x2f).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write));
+}
+
+void ioc2_full_house_device::map(address_map &map)
+{
+ base_map(map);
+}
+
+void ioc2_full_house_device::int2_map(address_map &map)
+{
+ map(0x00, 0x00).r(FUNC(ioc2_full_house_device::local_status_r<0>));
+ map(0x01, 0x01).rw(FUNC(ioc2_full_house_device::local_mask_r<0>), FUNC(ioc2_full_house_device::local_mask_w<0>));
+ map(0x02, 0x02).r(FUNC(ioc2_full_house_device::local_status_r<1>));
+ map(0x03, 0x03).rw(FUNC(ioc2_full_house_device::local_mask_r<1>), FUNC(ioc2_full_house_device::local_mask_w<1>));
+ map(0x04, 0x04).r(FUNC(ioc2_full_house_device::map_status_r));
+ map(0x05, 0x05).rw(FUNC(ioc2_full_house_device::map_mask_r<0>), FUNC(ioc2_full_house_device::map_mask_w<0>));
+ map(0x06, 0x06).rw(FUNC(ioc2_full_house_device::map_mask_r<1>), FUNC(ioc2_full_house_device::map_mask_w<1>));
+ map(0x08, 0x08).w(FUNC(ioc2_full_house_device::timer_int_clear_w));
+ map(0x0c, 0x0f).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write));
+}
+
+void ioc2_device::set_local_int_mask(int channel, uint8_t mask)
+{
+ uint8_t old = m_int3_local_mask_reg[channel];
+ m_int3_local_mask_reg[channel] = mask;
+ bool old_line = (old & m_int3_local_status_reg[channel]) != 0;
+ bool new_line = (m_int3_local_mask_reg[channel] & m_int3_local_status_reg[channel]) != 0;
+ if (old_line != new_line)
+ {
+ const uint8_t int_bits = (m_int3_local_mask_reg[channel] & m_int3_local_status_reg[channel]);
+ m_maincpu->set_input_line(channel, int_bits != 0 ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+void ioc2_device::set_map_int_mask(int channel, uint8_t mask)
+{
+ m_int3_map_mask_reg[channel] = mask;
+ check_mappable_interrupt(channel);
+}
+
+void ioc2_device::set_timer_int_clear(uint8_t data)
+{
+ if (BIT(data, 0))
+ {
+ LOGMASKED(LOG_IRQS, "Lowering IRQ line 2\n");
+ m_maincpu->set_input_line(2, CLEAR_LINE);
+ }
+ if (BIT(data, 1))
+ {
+ LOGMASKED(LOG_IRQS, "Lowering IRQ line 3\n");
+ m_maincpu->set_input_line(3, CLEAR_LINE);
+ }
+}
+
+void ioc2_device::handle_reset_reg_write(uint8_t data)
+{
+ // guinness/fullhouse-specific implementations can handle bit 3 being used for ISDN reset on Indy only and bit 2 for EISA reset on Indigo 2 only, but for now we do nothing with it
+ if (!BIT(data, 1))
+ {
+ //m_kbdc->reset();
+ }
+ m_reset_reg = 0;
+}
+
+INPUT_CHANGED_MEMBER( ioc2_device::power_button )
+{
+ if (!newval)
+ m_front_panel_reg |= FRONT_PANEL_POWER_BUTTON_INT;
+ else
+ m_front_panel_reg &= ~FRONT_PANEL_POWER_BUTTON_INT;
+
+ if (m_front_panel_reg & FRONT_PANEL_INT_MASK)
+ raise_local_irq(1, INT3_LOCAL1_PANEL);
+}
+
+INPUT_CHANGED_MEMBER( ioc2_device::volume_up )
+{
+ if (!newval)
+ {
+ m_front_panel_reg |= FRONT_PANEL_VOL_UP_INT;
+ m_front_panel_reg &= ~FRONT_PANEL_VOL_UP_HOLD;
+ }
+ else
+ {
+ m_front_panel_reg |= FRONT_PANEL_VOL_UP_HOLD;
+ }
+
+ if (m_front_panel_reg & FRONT_PANEL_INT_MASK)
+ raise_local_irq(1, INT3_LOCAL1_PANEL);
+}
+
+INPUT_CHANGED_MEMBER( ioc2_device::volume_down )
+{
+ if (!newval)
+ {
+ m_front_panel_reg |= FRONT_PANEL_VOL_DOWN_INT;
+ m_front_panel_reg &= ~FRONT_PANEL_VOL_DOWN_HOLD;
+ }
+ else
+ {
+ m_front_panel_reg |= FRONT_PANEL_VOL_DOWN_HOLD;
+ }
+
+ if (m_front_panel_reg & FRONT_PANEL_INT_MASK)
+ raise_local_irq(1, INT3_LOCAL1_PANEL);
+}
+
+void ioc2_device::gio_int0_w(int state)
+{
+ if (state == ASSERT_LINE)
+ raise_local_irq(0, ioc2_device::INT3_LOCAL0_FIFO);
+ else
+ lower_local_irq(0, ioc2_device::INT3_LOCAL0_FIFO);
+}
+
+void ioc2_device::gio_int1_w(int state)
+{
+ if (state == ASSERT_LINE)
+ raise_local_irq(0, ioc2_device::INT3_LOCAL0_GRAPHICS);
+ else
+ lower_local_irq(0, ioc2_device::INT3_LOCAL0_GRAPHICS);
+}
+
+void ioc2_device::gio_int2_w(int state)
+{
+ if (state == ASSERT_LINE)
+ raise_local_irq(1, ioc2_device::INT3_LOCAL1_RETRACE);
+ else
+ lower_local_irq(1, ioc2_device::INT3_LOCAL1_RETRACE);
+}
+
+void ioc2_device::hpc_dma_done_w(int state)
+{
+ if (state)
+ raise_local_irq(1, ioc2_device::INT3_LOCAL1_HPC_DMA);
+ else
+ lower_local_irq(1, ioc2_device::INT3_LOCAL1_HPC_DMA);
+}
+
+void ioc2_device::mc_dma_done_w(int state)
+{
+ if (state == ASSERT_LINE)
+ raise_local_irq(0, ioc2_device::INT3_LOCAL0_MC_DMA);
+ else
+ lower_local_irq(0, ioc2_device::INT3_LOCAL0_MC_DMA);
+}
+
+void ioc2_device::scsi0_int_w(int state)
+{
+ if (state)
+ raise_local_irq(0, ioc2_device::INT3_LOCAL0_SCSI0);
+ else
+ lower_local_irq(0, ioc2_device::INT3_LOCAL0_SCSI0);
+}
+
+void ioc2_device::scsi1_int_w(int state)
+{
+ if (state)
+ raise_local_irq(0, ioc2_device::INT3_LOCAL0_SCSI1);
+ else
+ lower_local_irq(0, ioc2_device::INT3_LOCAL0_SCSI1);
+}
+
+void ioc2_device::enet_int_w(int state)
+{
+ if (state)
+ raise_local_irq(0, ioc2_device::INT3_LOCAL0_ETHERNET);
+ else
+ lower_local_irq(0, ioc2_device::INT3_LOCAL0_ETHERNET);
+}
+
+void ioc2_device::video_int_w(int state)
+{
+ if (state)
+ raise_local_irq(1, ioc2_device::INT3_LOCAL1_VIDEO);
+ else
+ lower_local_irq(1, ioc2_device::INT3_LOCAL1_VIDEO);
+}