summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-10-25 04:28:35 +1100
committer Vas Crabb <vas@vastheman.com>2020-10-25 04:28:35 +1100
commit3677f57a4ab0b713f7d50b153ebafc8517524c4b (patch)
tree37376e9710d6d711233632e2344f564d71673b49
parent07ab3966ebe1ced0eb98950b870a6d8ab8740990 (diff)
bus/a2bus: Re-wrote Apple II Parallel Interface Card emulation.
-rw-r--r--src/devices/bus/a2bus/a2pic.cpp580
-rw-r--r--src/devices/bus/a2bus/a2pic.h128
-rw-r--r--src/devices/bus/a2bus/grapplerplus.cpp4
3 files changed, 478 insertions, 234 deletions
diff --git a/src/devices/bus/a2bus/a2pic.cpp b/src/devices/bus/a2bus/a2pic.cpp
index 21c749eb50c..c0232ea74dd 100644
--- a/src/devices/bus/a2bus/a2pic.cpp
+++ b/src/devices/bus/a2bus/a2pic.cpp
@@ -1,292 +1,492 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-/*********************************************************************
+// copyright-holders:Vas Crabb
+#include "emu.h"
+#include "a2pic.h"
- a2pic.c
+//#define VERBOSE 1
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
- Apple II Parallel Interface Card (670-0021)
+namespace {
-*********************************************************************/
+ROM_START(pic)
+ ROM_REGION(0x0200, "prom", 0)
+ ROM_LOAD( "341-0057.7b", 0x0000, 0x0200, CRC(0a6b084b) SHA1(de8aa285dcac88b1cc80ec9128b092833f5174b6) )
+ROM_END
-#include "emu.h"
-#include "a2pic.h"
-/***************************************************************************
- PARAMETERS
-***************************************************************************/
+INPUT_PORTS_START(pic)
+ PORT_START("SW1")
+ PORT_DIPNAME(0x07, 0x07, "Strobe Length") PORT_DIPLOCATION("SW1:1,2,3")
+ PORT_DIPSETTING( 0x07, "1 microsecond")
+ PORT_DIPSETTING( 0x06, "3 microseconds")
+ PORT_DIPSETTING( 0x05, "5 microseconds")
+ PORT_DIPSETTING( 0x04, "7 microseconds")
+ PORT_DIPSETTING( 0x03, "9 microseconds")
+ PORT_DIPSETTING( 0x02, "11 microseconds")
+ PORT_DIPSETTING( 0x01, "13 microseconds")
+ PORT_DIPSETTING( 0x00, "15 microseconds")
+ PORT_DIPNAME(0x08, 0x00, "Strobe Output Polarity") PORT_DIPLOCATION("SW1:4") PORT_CHANGED_MEMBER(DEVICE_SELF, a2bus_pic_device, sw1_strobe, 0)
+ PORT_DIPSETTING( 0x08, "Positive")
+ PORT_DIPSETTING( 0x00, "Negative")
+ PORT_DIPNAME(0x10, 0x00, "Acknowledge Input Polarity") PORT_DIPLOCATION("SW1:5") PORT_CHANGED_MEMBER(DEVICE_SELF, a2bus_pic_device, sw1_ack, 0)
+ PORT_DIPSETTING( 0x10, "Positive")
+ PORT_DIPSETTING( 0x00, "Negative")
+ PORT_DIPNAME(0x20, 0x20, "Firmware") PORT_DIPLOCATION("SW1:6") PORT_CHANGED_MEMBER(DEVICE_SELF, a2bus_pic_device, sw1_firmware, 0)
+ PORT_DIPSETTING( 0x20, "Parallel Printer") // ROM #341-0005 - auto LF after CR
+ PORT_DIPSETTING( 0x00, "Centronics") // ROM #341-0019 - no auto LF after CR
+ PORT_DIPNAME(0x40, 0x40, "Interrupt") PORT_DIPLOCATION("SW1:7") PORT_CHANGED_MEMBER(DEVICE_SELF, a2bus_pic_device, sw1_irq, 0)
+ PORT_DIPSETTING( 0x40, "Disabled")
+ PORT_DIPSETTING( 0x00, "Enabled")
+
+ PORT_START("X")
+ PORT_CONFNAME(0x01, 0x01, "PROM Addressing")
+ PORT_CONFSETTING( 0x00, "Flat (X1)")
+ PORT_CONFSETTING( 0x01, "Standard (X2)")
+ PORT_CONFNAME(0x02, 0x02, "Data Output") PORT_CHANGED_MEMBER(DEVICE_SELF, a2bus_pic_device, x_data_out, 0)
+ PORT_CONFSETTING( 0x00, "Disabled (X3)")
+ PORT_CONFSETTING( 0x02, "Enabled (X4)")
+ PORT_CONFNAME(0x04, 0x04, "Character Width") PORT_CHANGED_MEMBER(DEVICE_SELF, a2bus_pic_device, x_char_width, 0)
+ PORT_CONFSETTING( 0x00, "7-bit (X5)")
+ PORT_CONFSETTING( 0x04, "8-bit (X6)")
+INPUT_PORTS_END
-//**************************************************************************
-// GLOBAL VARIABLES
-//**************************************************************************
+} // anonymous namespace
-DEFINE_DEVICE_TYPE(A2BUS_PIC, a2bus_pic_device, "a2pic", "Apple Parallel Interface Card")
-#define PIC_ROM_REGION "pic_rom"
-#define PIC_CENTRONICS_TAG "pic_ctx"
-ROM_START( pic )
- ROM_REGION(0x000200, PIC_ROM_REGION, 0)
- ROM_LOAD( "341-0057.bin", 0x000000, 0x000200, CRC(0d2d84ee) SHA1(bfc5b863d37e59875a6159528eb0f2b6082063b5) )
-ROM_END
+DEFINE_DEVICE_TYPE(A2BUS_PIC, a2bus_pic_device, "a2pic", "Apple II Parallel Interface Card")
-static INPUT_PORTS_START( pic )
- PORT_START("DSW1")
- PORT_DIPNAME( 0x07, 0x00, "Strobe length (SW1-3)" )
- PORT_DIPSETTING( 0x00, "1 microsecond" )
- PORT_DIPSETTING( 0x01, "3 microseconds" )
- PORT_DIPSETTING( 0x02, "5 microseconds" )
- PORT_DIPSETTING( 0x03, "7 microseconds" )
- PORT_DIPSETTING( 0x04, "9 microseconds" )
- PORT_DIPSETTING( 0x05, "11 microseconds" )
- PORT_DIPSETTING( 0x06, "13 microseconds" )
- PORT_DIPSETTING( 0x07, "15 microseconds" )
-
- PORT_DIPNAME( 0x08, 0x08, "Strobe polarity (SW4)" )
- PORT_DIPSETTING( 0x00, "Positive" )
- PORT_DIPSETTING( 0x08, "Negative" )
-
- PORT_DIPNAME( 0x10, 0x10, "Acknowledge polarity (SW5)" )
- PORT_DIPSETTING( 0x00, "Positive" )
- PORT_DIPSETTING( 0x10, "Negative" )
-
- PORT_DIPNAME( 0x20, 0x20, "Firmware (SW6)" )
- PORT_DIPSETTING( 0x00, "Parallel Printer (341-0005)" )
- PORT_DIPSETTING( 0x20, "Centronics (341-0019)" )
-
- PORT_DIPNAME( 0x40, 0x00, "Use interrupts (SW7)" )
- PORT_DIPSETTING( 0x00, "Off" )
- PORT_DIPSETTING( 0x40, "On" )
-INPUT_PORTS_END
-//-------------------------------------------------
-// input_ports - device-specific input ports
-//-------------------------------------------------
-ioport_constructor a2bus_pic_device::device_input_ports() const
+a2bus_pic_device::a2bus_pic_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, A2BUS_PIC, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_printer_conn(*this, "prn"),
+ m_printer_out(*this, "prn_out"),
+ m_input_sw1(*this, "SW1"),
+ m_input_x(*this, "X"),
+ m_prom(*this, "prom"),
+ m_strobe_timer(nullptr),
+ m_firmware_base(0x0000U),
+ m_data_latch(0x00U),
+ m_autostrobe_disable(0U),
+ m_ack_latch(0U),
+ m_irq_enable(0U),
+ m_ack_in(1U),
+ m_perror_in(1U),
+ m_select_in(1U),
+ m_fault_in(1U)
{
- return INPUT_PORTS_NAME( pic );
}
-//-------------------------------------------------
-// device_add_mconfig - add device configuration
-//-------------------------------------------------
-void a2bus_pic_device::device_add_mconfig(machine_config &config)
-{
- CENTRONICS(config, m_ctx, centronics_devices, "printer");
- m_ctx->set_data_input_buffer(m_ctx_data_in);
- m_ctx->ack_handler().set(FUNC(a2bus_pic_device::ack_w));
-
- INPUT_BUFFER(config, m_ctx_data_in);
- OUTPUT_LATCH(config, m_ctx_data_out);
- m_ctx->set_output_latch(*m_ctx_data_out);
-}
-//-------------------------------------------------
-// rom_region - device-specific ROM region
-//-------------------------------------------------
+//----------------------------------------------
+// DIP switch/jumper handlers
+//----------------------------------------------
-const tiny_rom_entry *a2bus_pic_device::device_rom_region() const
+INPUT_CHANGED_MEMBER(a2bus_pic_device::sw1_strobe)
{
- return ROM_NAME( pic );
+ m_printer_conn->write_strobe(BIT(m_input_sw1->read(), 3) ^ (m_strobe_timer->enabled() ? 0U : 1U));
}
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
-a2bus_pic_device::a2bus_pic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- a2bus_pic_device(mconfig, A2BUS_PIC, tag, owner, clock)
+INPUT_CHANGED_MEMBER(a2bus_pic_device::sw1_ack)
{
+ if (m_ack_in != BIT(m_input_sw1->read(), 4))
+ set_ack_latch();
}
-a2bus_pic_device::a2bus_pic_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_dsw1(*this, "DSW1"),
- m_ctx(*this, PIC_CENTRONICS_TAG),
- m_ctx_data_in(*this, "ctx_data_in"),
- m_ctx_data_out(*this, "ctx_data_out"), m_rom(nullptr),
- m_started(false), m_ack(0), m_irqenable(false), m_autostrobe(false), m_timer(nullptr)
+
+INPUT_CHANGED_MEMBER(a2bus_pic_device::sw1_firmware)
{
+ m_firmware_base = BIT(m_input_sw1->read(), 5) << 8;
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-void a2bus_pic_device::device_start()
+INPUT_CHANGED_MEMBER(a2bus_pic_device::sw1_irq)
{
- m_rom = device().machine().root_device().memregion(this->subtag(PIC_ROM_REGION).c_str())->base();
+ if (m_ack_latch && m_irq_enable)
+ {
+ if (BIT(m_input_sw1->read(), 6))
+ lower_slot_irq();
+ else
+ raise_slot_irq();
+ }
+}
- m_timer = timer_alloc(0, nullptr);
- m_timer->adjust(attotime::never);
- save_item(NAME(m_ack));
- save_item(NAME(m_irqenable));
- save_item(NAME(m_autostrobe));
+INPUT_CHANGED_MEMBER(a2bus_pic_device::x_data_out)
+{
+ if (m_data_latch && !BIT(m_input_x->read(), 1))
+ {
+ m_data_latch = 0x00U;
+ m_printer_out->write(0x00U);
+ }
}
-void a2bus_pic_device::device_reset()
+
+INPUT_CHANGED_MEMBER(a2bus_pic_device::x_char_width)
{
- m_started = true;
- m_ack = 0;
- m_irqenable = false;
- m_autostrobe = false;
- lower_slot_irq();
- m_timer->adjust(attotime::never);
-
- // set initial state of the strobe line depending on the dipswitch
- clear_strobe();
+ if (BIT(m_data_latch, 7))
+ m_printer_out->write(m_data_latch & (BIT(m_input_x->read(), 2) ? 0xffU : 0x7fU));
}
-void a2bus_pic_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
-{
- clear_strobe();
- m_timer->adjust(attotime::never);
-}
-/*-------------------------------------------------
- read_cnxx - called for reads from this card's cnxx space
--------------------------------------------------*/
+//----------------------------------------------
+// device_a2bus_card_interface implementation
+//----------------------------------------------
-uint8_t a2bus_pic_device::read_cnxx(uint8_t offset)
+u8 a2bus_pic_device::read_c0nx(u8 offset)
{
- m_autostrobe = true;
+ LOG("Read C0n%01X\n", offset);
- if (m_dsw1->read() & 0x20)
+ switch (offset & 0x07U)
{
- return m_rom[(offset&0xff) | 0x100];
+ case 3U:
+ return 0x97U | (m_perror_in << 5) | (m_select_in << 6) | (m_fault_in << 3);
+
+ case 4U:
+ return (m_ack_latch << 7) | (m_ack_in ^ BIT(m_input_sw1->read(), 4));
+
+ case 5U:
+ logerror("500ns negative strobe not implemented\n");
+ break;
+
+ case 6U:
+ enable_irq();
+ break;
+
+ case 7U:
+ reset_mode();
+ break;
}
- return m_rom[(offset&0xff)];
+ return 0x00U;
}
-/*-------------------------------------------------
- read_c0nx - called for reads from this card's c0nx space
--------------------------------------------------*/
-
-uint8_t a2bus_pic_device::read_c0nx(uint8_t offset)
+void a2bus_pic_device::write_c0nx(u8 offset, u8 data)
{
- uint8_t rv = 0;
+ LOG("Write C0n%01X=%02X\n", offset, data);
- switch (offset)
+ switch (offset & 0x07U)
{
- case 3:
- return m_ctx_data_in->read();
-
- case 4:
- rv = m_ack;
+ case 0U:
+ {
+ ioport_value const x(m_input_x->read());
- // clear flip-flop
- if (m_dsw1->read() & 0x10) // negative polarity
+ // latch output data - remember MSB can be forced low by jumper
+ if (BIT(x, 1))
{
- m_ack |= 0x80;
+ LOG("Latch data %02X\n", data);
+ m_data_latch = data;
+ m_printer_out->write(data & (BIT(x, 2) ? 0xffU : 0x7fU));
}
else
{
- m_ack &= ~0x80;
+ LOG("Output disabled, not latching data\n");
}
- return rv;
+ // start strobe if autostrobe is enabled
+ if (!m_autostrobe_disable)
+ start_strobe();
+ }
+ break;
- case 6: // does reading this really work?
- m_irqenable = true;
- break;
+ case 2U:
+ start_strobe();
+ break;
- case 7:
- m_irqenable = false;
- m_autostrobe = false;
- lower_slot_irq();
- break;
+ case 5U:
+ logerror("500ns negative strobe not implemented\n");
+ break;
- }
+ case 6U:
+ enable_irq();
+ break;
- return 0;
+ case 7U:
+ reset_mode();
+ break;
+ }
}
-/*-------------------------------------------------
- write_c0nx - called for writes to this card's c0nx space
--------------------------------------------------*/
-void a2bus_pic_device::write_c0nx(uint8_t offset, uint8_t data)
+u8 a2bus_pic_device::read_cnxx(u8 offset)
{
- switch (offset)
+ if (BIT(m_input_x->read(), 0))
{
- case 0: // set data out and send a strobe
- m_ctx_data_out->write(data);
+ if (!BIT(offset, 6) || (BIT(offset, 7) && !m_ack_latch))
+ offset |= 0x40U;
+ else
+ offset &= 0xbfU;
+ }
- if (m_autostrobe)
- {
- start_strobe();
- }
- break;
+ if (!machine().side_effects_disabled())
+ {
+ if (m_autostrobe_disable)
+ LOG("Enabling autostrobe\n");
+ m_autostrobe_disable = 0U;
+ }
- case 2: // send a strobe
- start_strobe();
- break;
+ return m_prom[m_firmware_base | offset];
+}
- case 6: // enable interrupt on ACK
- m_irqenable = true;
- break;
- case 7: // disable and acknowledge IRQ, reset ACK flip-flop, disable autostrobe
- m_irqenable = false;
- m_autostrobe = false;
- lower_slot_irq();
- break;
- }
+void a2bus_pic_device::write_cnxx(u8 offset, u8 data)
+{
+ LOG("Write Cn%02X=%02X (bus conflict)\n", offset, data);
+
+ if (m_autostrobe_disable)
+ LOG("Enabling autostrobe\n");
+ m_autostrobe_disable = 0U;
+}
+
+
+
+//----------------------------------------------
+// device_t implementation
+//----------------------------------------------
+
+tiny_rom_entry const *a2bus_pic_device::device_rom_region() const
+{
+ return ROM_NAME(pic);
+}
+
+
+void a2bus_pic_device::device_add_mconfig(machine_config &config)
+{
+ CENTRONICS(config, m_printer_conn, centronics_devices, "printer");
+ m_printer_conn->ack_handler().set(FUNC(a2bus_pic_device::ack_w));
+ m_printer_conn->perror_handler().set(FUNC(a2bus_pic_device::perror_w));
+ m_printer_conn->select_handler().set(FUNC(a2bus_pic_device::select_w));
+ m_printer_conn->fault_handler().set(FUNC(a2bus_pic_device::fault_w));
+
+ OUTPUT_LATCH(config, m_printer_out);
+ m_printer_conn->set_output_latch(*m_printer_out);
+}
+
+
+ioport_constructor a2bus_pic_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(pic);
+}
+
+
+void a2bus_pic_device::device_start()
+{
+ m_strobe_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(a2bus_pic_device::release_strobe), this));
+
+ m_firmware_base = 0x0100U;
+ m_data_latch = 0xffU;
+
+ save_item(NAME(m_data_latch));
+ save_item(NAME(m_autostrobe_disable));
+ save_item(NAME(m_ack_latch));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_ack_in));
+ save_item(NAME(m_perror_in));
+ save_item(NAME(m_select_in));
+ save_item(NAME(m_fault_in));
}
-WRITE_LINE_MEMBER( a2bus_pic_device::ack_w )
+
+void a2bus_pic_device::device_reset()
{
- if (m_started)
+ ioport_value const sw1(m_input_sw1->read());
+ ioport_value const x(m_input_x->read());
+
+ m_firmware_base = BIT(sw1, 5) << 8;
+ m_autostrobe_disable = 1U;
+
+ if (!BIT(x, 1))
{
- uint8_t dsw1 = m_dsw1->read();
+ m_data_latch = 0x00U;
+ m_printer_out->write(0x00U);
+ }
- if (dsw1 & 0x10) // negative polarity
- {
- m_ack = (state == ASSERT_LINE) ? 0x00 : 0x80;
- }
- else
+ m_printer_conn->write_strobe(BIT(sw1, 3) ^ (m_strobe_timer->enabled() ? 0U : 1U));
+
+ reset_mode();
+}
+
+
+
+//----------------------------------------------
+// printer status inputs
+//----------------------------------------------
+
+WRITE_LINE_MEMBER(a2bus_pic_device::ack_w)
+{
+ if (bool(state) != bool(m_ack_in))
+ {
+ m_ack_in = state ? 1U : 0U;
+ LOG("/ACK=%u\n", m_ack_in);
+ if (started() && (m_ack_in != BIT(m_input_sw1->read(), 4)))
{
- m_ack = (state == ASSERT_LINE) ? 0x80 : 0x00;
+ LOG("Active /ACK edge\n");
+ set_ack_latch();
}
+ }
+}
+
+
+WRITE_LINE_MEMBER(a2bus_pic_device::perror_w)
+{
+ if (bool(state) != bool(m_perror_in))
+ {
+ m_perror_in = state ? 1U : 0U;
+ LOG("PAPER EMPTY=%u\n", m_perror_in);
+ }
+}
- m_ack |= 0x40; // set ACK flip-flop
- if ((dsw1 & 0x40) && (m_irqenable))
+WRITE_LINE_MEMBER(a2bus_pic_device::select_w)
+{
+ if (bool(state) != bool(m_select_in))
+ {
+ m_select_in = state ? 1U : 0U;
+ LOG("SELECT=%u\n", m_select_in);
+ }
+}
+
+
+WRITE_LINE_MEMBER(a2bus_pic_device::fault_w)
+{
+ if (bool(state) != bool(m_fault_in))
+ {
+ m_fault_in = state ? 1U : 0U;
+ LOG("/FAULT=%u\n", m_fault_in);
+ }
+}
+
+
+
+//----------------------------------------------
+// timer handlers
+//----------------------------------------------
+
+TIMER_CALLBACK_MEMBER(a2bus_pic_device::release_strobe)
+{
+ int const state(BIT(~m_input_sw1->read(), 3));
+ LOG("Output /STROBE=%d\n", state);
+ m_printer_conn->write_strobe(state);
+}
+
+
+
+//----------------------------------------------
+// helpers
+//----------------------------------------------
+
+void a2bus_pic_device::reset_mode()
+{
+ if (!m_autostrobe_disable)
+ LOG("Disabling autostrobe\n");
+ else
+ LOG("Autostrobe already disabled\n");
+ m_autostrobe_disable = 1U;
+ disable_irq();
+ set_ack_latch();
+}
+
+
+void a2bus_pic_device::start_strobe()
+{
+ ioport_value const sw1(m_input_sw1->read());
+ unsigned const cycles(15U - ((sw1 & 0x07U) << 1));
+ int const state(BIT(sw1, 3));
+ if (!m_strobe_timer->enabled())
+ {
+ LOG("Output /STROBE=%d for %u cycles\n", state, cycles);
+ clear_ack_latch();
+ m_printer_conn->write_strobe(state);
+ }
+ else
+ {
+ LOG("Adjust /STROBE=%d remaining to %u cycles\n", state, cycles);
+ }
+ m_strobe_timer->adjust(attotime::from_ticks(cycles, clock()));
+}
+
+
+void a2bus_pic_device::set_ack_latch()
+{
+ if (m_strobe_timer->enabled())
+ {
+ LOG("Active strobe prevents acknowledge latch from being set\n");
+ }
+ else if (!m_ack_latch)
+ {
+ LOG("Setting acknowledge latch\n");
+ m_ack_latch = 1U;
+ if (m_irq_enable && !BIT(m_input_sw1->read(), 6))
{
+ LOG("Asserting slot IRQ\n");
raise_slot_irq();
}
}
+ else
+ {
+ LOG("Acknowledge latch already set\n");
+ }
}
-void a2bus_pic_device::start_strobe()
-{
- int usec = ((m_dsw1->read() & 7) * 2) + 1; // strobe length in microseconds
- if (m_dsw1->read() & 0x8) // negative polarity
+void a2bus_pic_device::clear_ack_latch()
+{
+ if (m_ack_latch)
{
- m_ctx->write_strobe(CLEAR_LINE);
+ LOG("Clearing acknowledge latch\n");
+ m_ack_latch = 0U;
+ if (m_irq_enable && !BIT(m_input_sw1->read(), 6))
+ {
+ LOG("Releasing slot IRQ\n");
+ lower_slot_irq();
+ }
}
else
{
- m_ctx->write_strobe(ASSERT_LINE);
+ LOG("Acknowledge latch already clear\n");
}
+}
+
- m_timer->adjust(attotime::from_usec(usec), 0, attotime::never);
+void a2bus_pic_device::enable_irq()
+{
+ if (!m_irq_enable)
+ {
+ LOG("Enabling IRQ\n");
+ m_irq_enable = 1U;
+ if (m_ack_latch && !BIT(m_input_sw1->read(), 6))
+ {
+ LOG("Asserting slot IRQ\n");
+ raise_slot_irq();
+ }
+ }
+ else
+ {
+ LOG("IRQ already enabled\n");
+ }
}
-void a2bus_pic_device::clear_strobe()
+
+void a2bus_pic_device::disable_irq()
{
- if (m_dsw1->read() & 0x8) // negative polarity
+ if (m_irq_enable)
{
- m_ctx->write_strobe(ASSERT_LINE);
+ LOG("Disabling IRQ\n");
+ m_irq_enable = 0U;
+ if (m_ack_latch && !BIT(m_input_sw1->read(), 6))
+ {
+ LOG("Releasing slot IRQ\n");
+ lower_slot_irq();
+ }
}
else
{
- m_ctx->write_strobe(CLEAR_LINE);
+ LOG("IRQ already disabled\n");
}
}
diff --git a/src/devices/bus/a2bus/a2pic.h b/src/devices/bus/a2bus/a2pic.h
index 755700ef0b0..283dd537e7c 100644
--- a/src/devices/bus/a2bus/a2pic.h
+++ b/src/devices/bus/a2bus/a2pic.h
@@ -1,13 +1,40 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont
+// copyright-holders:Vas Crabb
/*********************************************************************
- a2pic.h
-
- Apple II Parallel Interface Card
+ Apple II Parallel Interface Card (670-0021)
+
+ DB25 connector, with Centronics assignments:
+
+ Data In, Bit 0 1
+ Signal Ground 2 19 GND
+ Data In, Bit 2 3
+ Signal Ground 4
+ Data Out, Bit 0 5 2 D0
+ Data Out, Bit 1 6 3 D1
+ (blocked)* 7
+ Data Out, Bit 2 8 4 D2
+ -- 9
+ -- 10
+ Data Out, Bit 5 11 7 D5
+ Data Out, Bit 6 12 8 D6
+ Data Out, Bit 7 13 9 D7
+ Data In, Bit 4 14
+ Strobe Out 15 1 /STROBE
+ Acknowledge In 16 10 /ACK
+ Data In, Bit 1 17
+ Data In, Bit 7 18 18 +5V PULLUP
+ Data In, Bit 5 19 12 POUT
+ Signal Ground 20
+ Data In, Bit 6 21 13 SEL
+ Data Out, Bit 3 22 5 D3
+ Data Out, Bit 4 23 6 D4
+ Signal Ground 24 16 0V
+ Data In, Bit 3 25 32 /FAULT
+
+ *wired to 500ns strobe but connector hole is blocked
*********************************************************************/
-
#ifndef MAME_BUS_A2BUS_A2PIC_H
#define MAME_BUS_A2BUS_A2PIC_H
@@ -16,53 +43,70 @@
#include "a2bus.h"
#include "bus/centronics/ctronics.h"
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-class a2bus_pic_device:
- public device_t,
- public device_a2bus_card_interface
+class a2bus_pic_device : public device_t, public device_a2bus_card_interface
{
public:
- // construction/destruction
- a2bus_pic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ a2bus_pic_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // DIP switch/jumper handlers
+ DECLARE_INPUT_CHANGED_MEMBER(sw1_strobe);
+ DECLARE_INPUT_CHANGED_MEMBER(sw1_ack);
+ DECLARE_INPUT_CHANGED_MEMBER(sw1_firmware);
+ DECLARE_INPUT_CHANGED_MEMBER(sw1_irq);
+ DECLARE_INPUT_CHANGED_MEMBER(x_data_out);
+ DECLARE_INPUT_CHANGED_MEMBER(x_char_width);
+
+ // device_a2bus_card_interface implementation
+ virtual u8 read_c0nx(u8 offset) override;
+ virtual void write_c0nx(u8 offset, u8 data) override;
+ virtual u8 read_cnxx(u8 offset) override;
+ virtual void write_cnxx(u8 offset, u8 data) override;
protected:
- a2bus_pic_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
-
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ // device_t implementation
+ virtual tiny_rom_entry const *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
- virtual const tiny_rom_entry *device_rom_region() const override;
virtual ioport_constructor device_input_ports() 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;
- virtual uint8_t read_cnxx(uint8_t offset) override;
-
- void start_strobe();
- void clear_strobe();
-
- required_ioport m_dsw1;
+private:
+ // printer status inputs
+ DECLARE_WRITE_LINE_MEMBER(ack_w);
+ DECLARE_WRITE_LINE_MEMBER(perror_w);
+ DECLARE_WRITE_LINE_MEMBER(select_w);
+ DECLARE_WRITE_LINE_MEMBER(fault_w);
- required_device<centronics_device> m_ctx;
- required_device<input_buffer_device> m_ctx_data_in;
- required_device<output_latch_device> m_ctx_data_out;
+ // timer handlers
+ TIMER_CALLBACK_MEMBER(release_strobe);
-private:
- DECLARE_WRITE_LINE_MEMBER( ack_w );
-
- uint8_t *m_rom;
- bool m_started;
- uint8_t m_ack;
- bool m_irqenable;
- bool m_autostrobe;
- emu_timer *m_timer;
+ // helpers
+ void reset_mode();
+ void start_strobe();
+ void set_ack_latch();
+ void clear_ack_latch();
+ void enable_irq();
+ void disable_irq();
+
+ required_device<centronics_device> m_printer_conn;
+ required_device<output_latch_device> m_printer_out;
+ required_ioport m_input_sw1;
+ required_ioport m_input_x;
+ required_region_ptr<u8> m_prom;
+ emu_timer * m_strobe_timer;
+
+ u16 m_firmware_base; // controlled by SW6
+ u8 m_data_latch; // 9B
+ u8 m_autostrobe_disable; // 2A pin 8
+ u8 m_ack_latch; // 2A pin 6
+ u8 m_irq_enable; // 2B pin 9
+ u8 m_ack_in;
+ u8 m_perror_in; // DI5
+ u8 m_select_in; // DI6
+ u8 m_fault_in; // DI3
};
-// device type definition
+
DECLARE_DEVICE_TYPE(A2BUS_PIC, a2bus_pic_device)
-#endif // MAME_BUS_A2BUS_A2PIC_H
+#endif // MAME_BUS_A2BUS_A2PIC_H
diff --git a/src/devices/bus/a2bus/grapplerplus.cpp b/src/devices/bus/a2bus/grapplerplus.cpp
index 99e0f69f78f..480cfa1c8f9 100644
--- a/src/devices/bus/a2bus/grapplerplus.cpp
+++ b/src/devices/bus/a2bus/grapplerplus.cpp
@@ -76,7 +76,7 @@ a2bus_grapplerplus_device::a2bus_grapplerplus_device(machine_config const &mconf
INPUT_CHANGED_MEMBER(a2bus_grapplerplus_device::sw_msb)
{
if (BIT(m_data_latch, 7))
- m_printer_out->write(m_data_latch & ((BIT(m_s1->read(), 3) ? 0xffU : 0x7fU)));
+ m_printer_out->write(m_data_latch & (BIT(m_s1->read(), 3) ? 0xffU : 0x7fU));
}
@@ -106,7 +106,7 @@ void a2bus_grapplerplus_device::write_c0nx(u8 offset, u8 data)
// latch output data - remember MSB can be forced low by DIP switch
LOG("Latch data %02X\n", data);
m_data_latch = data;
- m_printer_out->write(data & ((BIT(m_s1->read(), 3) ? 0xffU : 0x7fU)));
+ m_printer_out->write(data & (BIT(m_s1->read(), 3) ? 0xffU : 0x7fU));
// clearing the ACK latch will acknowledge an interrupt
if (m_ack_in)