summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/a1bus
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
committer Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
commitf88cefad27a1737c76e09d99c9fb43e173506081 (patch)
tree2d8167d03579c46e226471747eb4407bd00ed6fa /src/devices/bus/a1bus
parente92ac9e0fa8e99869894bea00589bbb526be30aa (diff)
Move all devices into separate part of src tree (nw)
Diffstat (limited to 'src/devices/bus/a1bus')
-rw-r--r--src/devices/bus/a1bus/a1bus.c204
-rw-r--r--src/devices/bus/a1bus/a1bus.h145
-rw-r--r--src/devices/bus/a1bus/a1cassette.c201
-rw-r--r--src/devices/bus/a1bus/a1cassette.h53
-rw-r--r--src/devices/bus/a1bus/a1cffa.c156
-rw-r--r--src/devices/bus/a1bus/a1cffa.h53
6 files changed, 812 insertions, 0 deletions
diff --git a/src/devices/bus/a1bus/a1bus.c b/src/devices/bus/a1bus/a1bus.c
new file mode 100644
index 00000000000..7012d11a81b
--- /dev/null
+++ b/src/devices/bus/a1bus/a1bus.c
@@ -0,0 +1,204 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ a1bus.c - Apple I slot bus and card emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "a1bus.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A1BUS_SLOT = &device_creator<a1bus_slot_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// a1bus_slot_device - constructor
+//-------------------------------------------------
+a1bus_slot_device::a1bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, A1BUS_SLOT, "Apple I Slot", tag, owner, clock, "a1bus_slot", __FILE__),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+a1bus_slot_device::a1bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+void a1bus_slot_device::static_set_a1bus_slot(device_t &device, const char *tag, const char *slottag)
+{
+ a1bus_slot_device &a1bus_card = dynamic_cast<a1bus_slot_device &>(device);
+ a1bus_card.m_a1bus_tag = tag;
+ a1bus_card.m_a1bus_slottag = slottag;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a1bus_slot_device::device_start()
+{
+ device_a1bus_card_interface *dev = dynamic_cast<device_a1bus_card_interface *>(get_card_device());
+
+ if (dev) device_a1bus_card_interface::static_set_a1bus_tag(*dev, m_a1bus_tag, m_a1bus_slottag);
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A1BUS = &device_creator<a1bus_device>;
+
+void a1bus_device::static_set_cputag(device_t &device, const char *tag)
+{
+ a1bus_device &a1bus = downcast<a1bus_device &>(device);
+ a1bus.m_cputag = tag;
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// a1bus_device - constructor
+//-------------------------------------------------
+
+a1bus_device::a1bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, A1BUS, "Apple I Bus", tag, owner, clock, "a1bus", __FILE__),
+ m_out_irq_cb(*this),
+ m_out_nmi_cb(*this)
+{
+}
+
+a1bus_device::a1bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_out_irq_cb(*this),
+ m_out_nmi_cb(*this)
+{
+}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a1bus_device::device_start()
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+
+ // resolve callbacks
+ m_out_irq_cb.resolve_safe();
+ m_out_nmi_cb.resolve_safe();
+
+ // clear slot
+ m_device = NULL;
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void a1bus_device::device_reset()
+{
+}
+
+device_a1bus_card_interface *a1bus_device::get_a1bus_card()
+{
+ return m_device;
+}
+
+void a1bus_device::add_a1bus_card(device_a1bus_card_interface *card)
+{
+ m_device = card;
+}
+
+void a1bus_device::set_irq_line(int state)
+{
+ m_out_irq_cb(state);
+}
+
+void a1bus_device::set_nmi_line(int state)
+{
+ m_out_nmi_cb(state);
+}
+
+void a1bus_device::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler)
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler);
+}
+
+void a1bus_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data)
+{
+// printf("install_bank: %s @ %x->%x mask %x mirror %x\n", tag, start, end, mask, mirror);
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ space.install_readwrite_bank(start, end, mask, mirror, tag );
+ machine().root_device().membank(tag)->set_base(data);
+}
+
+// interrupt request from a1bus card
+WRITE_LINE_MEMBER( a1bus_device::irq_w ) { m_out_irq_cb(state); }
+WRITE_LINE_MEMBER( a1bus_device::nmi_w ) { m_out_nmi_cb(state); }
+
+//**************************************************************************
+// DEVICE CONFIG A1BUS CARD INTERFACE
+//**************************************************************************
+
+
+//**************************************************************************
+// DEVICE A1BUS CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_a1bus_card_interface - constructor
+//-------------------------------------------------
+
+device_a1bus_card_interface::device_a1bus_card_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device),
+ m_a1bus(NULL),
+ m_a1bus_tag(NULL)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_a1bus_card_interface - destructor
+//-------------------------------------------------
+
+device_a1bus_card_interface::~device_a1bus_card_interface()
+{
+}
+
+void device_a1bus_card_interface::static_set_a1bus_tag(device_t &device, const char *tag, const char *slottag)
+{
+ device_a1bus_card_interface &a1bus_card = dynamic_cast<device_a1bus_card_interface &>(device);
+ a1bus_card.m_a1bus_tag = tag;
+ a1bus_card.m_a1bus_slottag = slottag;
+}
+
+void device_a1bus_card_interface::set_a1bus_device()
+{
+ m_a1bus = dynamic_cast<a1bus_device *>(device().machine().device(m_a1bus_tag));
+ m_a1bus->add_a1bus_card(this);
+}
+
+void device_a1bus_card_interface::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler)
+{
+ m_a1bus->install_device(start, end, rhandler, whandler);
+}
+
+void device_a1bus_card_interface::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, char *tag, UINT8 *data)
+{
+ m_a1bus->install_bank(start, end, mask, mirror, tag, data);
+}
diff --git a/src/devices/bus/a1bus/a1bus.h b/src/devices/bus/a1bus/a1bus.h
new file mode 100644
index 00000000000..ecdb440f948
--- /dev/null
+++ b/src/devices/bus/a1bus/a1bus.h
@@ -0,0 +1,145 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ a1bus.h - Apple I expansion slot and card emulation
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __A1BUS_H__
+#define __A1BUS_H__
+
+#include "emu.h"
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_A1BUS_CPU(_cputag) \
+ a1bus_device::static_set_cputag(*device, _cputag);
+
+#define MCFG_A1BUS_OUT_IRQ_CB(_devcb) \
+ devcb = &a1bus_device::set_out_irq_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_A1BUS_OUT_NMI_CB(_devcb) \
+ devcb = &a1bus_device::set_out_nmi_callback(*device, DEVCB_##_devcb);
+
+#define MCFG_A1BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \
+ MCFG_DEVICE_ADD(_tag, A1BUS_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \
+ a1bus_slot_device::static_set_a1bus_slot(*device, _nbtag, _tag);
+#define MCFG_A1BUS_SLOT_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_A1BUS_ONBOARD_ADD(_nbtag, _tag, _dev_type, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, _dev_type, 0) \
+ MCFG_DEVICE_INPUT_DEFAULTS(_def_inp) \
+ device_a1bus_card_interface::static_set_a1bus_tag(*device, _nbtag, _tag);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class a1bus_device;
+
+class a1bus_slot_device : public device_t,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ a1bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ a1bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // inline configuration
+ static void static_set_a1bus_slot(device_t &device, const char *tag, const char *slottag);
+protected:
+ // configuration
+ const char *m_a1bus_tag, *m_a1bus_slottag;
+};
+
+// device type definition
+extern const device_type A1BUS_SLOT;
+
+
+class device_a1bus_card_interface;
+// ======================> a1bus_device
+class a1bus_device : public device_t
+{
+public:
+ // construction/destruction
+ a1bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ a1bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+ template<class _Object> static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast<a1bus_device &>(device).m_out_irq_cb.set_callback(object); }
+ template<class _Object> static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast<a1bus_device &>(device).m_out_nmi_cb.set_callback(object); }
+
+ void add_a1bus_card(device_a1bus_card_interface *card);
+ device_a1bus_card_interface *get_a1bus_card();
+
+ void set_irq_line(int state);
+ void set_nmi_line(int state);
+
+ void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler);
+ void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data);
+
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // internal state
+ cpu_device *m_maincpu;
+
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_nmi_cb;
+
+ device_a1bus_card_interface *m_device;
+ const char *m_cputag;
+};
+
+
+// device type definition
+extern const device_type A1BUS;
+
+// ======================> device_a1bus_card_interface
+
+// class representing interface-specific live a1bus card
+class device_a1bus_card_interface : public device_slot_card_interface
+{
+ friend class a1bus_device;
+public:
+ // construction/destruction
+ device_a1bus_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_a1bus_card_interface();
+
+ device_a1bus_card_interface *next() const { return m_next; }
+
+ void set_a1bus_device();
+
+ void raise_slot_irq() { m_a1bus->set_irq_line(ASSERT_LINE); }
+ void lower_slot_irq() { m_a1bus->set_irq_line(CLEAR_LINE); }
+ void raise_slot_nmi() { m_a1bus->set_nmi_line(ASSERT_LINE); }
+ void lower_slot_nmi() { m_a1bus->set_nmi_line(CLEAR_LINE); }
+
+ void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler);
+ void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, char *tag, UINT8 *data);
+
+ // inline configuration
+ static void static_set_a1bus_tag(device_t &device, const char *tag, const char *slottag);
+public:
+ a1bus_device *m_a1bus;
+ const char *m_a1bus_tag, *m_a1bus_slottag;
+ device_a1bus_card_interface *m_next;
+};
+
+#endif /* __A1BUS_H__ */
diff --git a/src/devices/bus/a1bus/a1cassette.c b/src/devices/bus/a1bus/a1cassette.c
new file mode 100644
index 00000000000..daa79b15ce5
--- /dev/null
+++ b/src/devices/bus/a1bus/a1cassette.c
@@ -0,0 +1,201 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ a1cassette.c
+
+ Apple I Cassette Interface
+
+*********************************************************************/
+
+#include "a1cassette.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+#define CASSETTE_ROM_REGION "casrom"
+
+const device_type A1BUS_CASSETTE = &device_creator<a1bus_cassette_device>;
+
+/* sound output */
+
+MACHINE_CONFIG_FRAGMENT( cassette )
+ MCFG_CASSETTE_ADD("cassette")
+ MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED)
+ MCFG_CASSETTE_INTERFACE("apple1_cass")
+MACHINE_CONFIG_END
+
+ROM_START( cassette )
+ /* 256-byte cassette interface ROM, in two 82s129 or mmi6301 256x4 proms at locations 3 and 4 on the cassette interface daughtercard (they are labeled "MMI 6301-IJ // 7623L // APPLE-A3" and "MMI 6301-IJ // 7623L // APPLE-A4") */
+ ROM_REGION(0x100, CASSETTE_ROM_REGION, 0)
+ ROM_LOAD_NIB_HIGH( "apple-a3.3", 0x0000, 0x0100, CRC(6eae8f52) SHA1(71906932727ef70952ef6afe6b08708df15cd67d) )
+ ROM_LOAD_NIB_LOW( "apple-a4.4", 0x0000, 0x0100, CRC(94efa977) SHA1(851f3bd6863859a1a6909179a5e5bf744b3d807e) )
+ROM_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor a1bus_cassette_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( cassette );
+}
+
+const rom_entry *a1bus_cassette_device::device_rom_region() const
+{
+ return ROM_NAME( cassette );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+a1bus_cassette_device::a1bus_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, A1BUS_CASSETTE, "Apple I cassette board", tag, owner, clock, "a1cass", __FILE__),
+ device_a1bus_card_interface(mconfig, *this),
+ m_cassette(*this, "cassette")
+{
+}
+
+a1bus_cassette_device::a1bus_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_a1bus_card_interface(mconfig, *this),
+ m_cassette(*this, "cassette")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a1bus_cassette_device::device_start()
+{
+ set_a1bus_device();
+
+ m_rom = device().machine().root_device().memregion(this->subtag(CASSETTE_ROM_REGION).c_str())->base();
+
+ install_device(0xc000, 0xc0ff, read8_delegate(FUNC(a1bus_cassette_device::cassette_r), this), write8_delegate(FUNC(a1bus_cassette_device::cassette_w), this));
+ install_bank(0xc100, 0xc1ff, 0, 0, (char *)"bank_a1cas", m_rom);
+
+ save_item(NAME(m_cassette_output_flipflop));
+}
+
+void a1bus_cassette_device::device_reset()
+{
+ m_cassette_output_flipflop = 0;
+}
+
+/*****************************************************************************
+** Cassette interface I/O
+**
+** The Apple I's cassette interface was a small card that plugged
+** into the expansion connector on the motherboard. (This was a
+** slot-type connector, separate from the motherboard's edge
+** connector, but with the same signals.) The cassette interface
+** provided separate cassette input and output jacks, some very
+** simple interface hardware, and 256 bytes of ROM containing the
+** cassette I/O code.
+**
+** The interface was mostly software-controlled. The only hardware
+** was an output flip-flop for generating the cassette output signal,
+** a National Semiconductor LM311 voltage comparator for generating a
+** digital signal from the analog cassette input, an input
+** signal-level LED, and some gates to control the interface logic
+** and address decoding. The cassette ROM code did most of the work
+** of generating and interpreting tape signals. It also contained
+** its own mini-monitor for issuing tape read and write commands.
+**
+** The cassette interface was assigned to the $C000-$CFFF block of
+** addresses, although it did not use most of the space in that
+** block. Addresses were mapped as follows:
+**
+** $C000-$C0FF: Cassette I/O space.
+** Any access here toggles the output signal.
+** $C000-$C07F: Cassette output only; input disabled.
+** Mirrors $C100-$C17F on reads.
+** $C080-$C0FF: Cassette input and output.
+** When input low, mirrors $C180-$C1FF on reads.
+** When input high, both odd and even addresses
+** mirror even ROM addresses $C180-$C1FE.
+** $C100-$C1FF: Cassette ROM code.
+**
+** Note the peculiar addressing scheme. Data was written simply
+** through repeated accesses, rather than by writing to an address.
+** Data was read by reading an odd input address and comparing the
+** ROM byte returned to detect signal changes.
+**
+** The standard tape signal was a simple square wave, although this
+** was often greatly distorted by the cassette recorder. A single
+** tape record consisted of a 10-second 800-Hz leader, followed by a
+** single short square-wave cycle used as a sync bit, followed by the
+** tape data. The data was encoded using a single square-wave cycle
+** for each bit; "1" bits were at 1000 Hz, "0" bits at 2000 Hz. (All
+** of these frequencies are approximate and could vary due to
+** differences in recorder speed.) Each byte was written starting
+** from the most significant bit; bytes were written from low to high
+** addresses. No error detection was provided. Multiple records
+** could be placed on a single tape.
+*****************************************************************************/
+
+/* The cassette output signal for writing tapes is generated by a
+ flip-flop which is toggled to produce the output waveform. Any
+ access to the cassette I/O range, whether a read or a write,
+ toggles this flip-flop. */
+void a1bus_cassette_device::cassette_toggle_output()
+{
+ m_cassette_output_flipflop = !m_cassette_output_flipflop;
+ m_cassette->output(m_cassette_output_flipflop ? 1.0 : -1.0);
+}
+
+READ8_MEMBER(a1bus_cassette_device::cassette_r)
+{
+ cassette_toggle_output();
+
+ if (offset <= 0x7f)
+ {
+ /* If the access is to address range $C000-$C07F, the cassette
+ input signal is ignored . In this case the value read
+ always comes from the corresponding cassette ROM location
+ in $C100-$C17F. */
+
+ return m_rom[offset];
+ }
+ else
+ {
+ /* For accesses to address range $C080-$C0FF, the cassette
+ input signal is enabled. If the signal is low, the value
+ read comes from the corresponding cassette ROM location in
+ $C180-$C1FF. If the signal is high, the low bit of the
+ address is masked before the corresponding cassette ROM
+ location is accessed; e.g., a read from $C081 would return
+ the ROM byte at $C180. The cassette ROM routines detect
+ changes in the cassette input signal by repeatedly reading
+ from $C081 and comparing the values read. */
+
+ /* (Don't try putting a non-zero "noise threshhold" here,
+ because it can cause tape header bits on real cassette
+ images to be misread as data bits.) */
+ if (m_cassette->input() > 0.0)
+ return m_rom[0xc100 + (offset & ~1)];
+ else
+ return m_rom[0xc100 + offset];
+ }
+}
+
+WRITE8_MEMBER(a1bus_cassette_device::cassette_w)
+{
+ /* Writes toggle the output flip-flop in the same way that reads
+ do; other than that they have no effect. Any repeated accesses
+ to the cassette I/O address range can be used to write data to
+ cassette, and the cassette ROM always uses reads to do this.
+ However, we still have to handle writes, since they may be done
+ by user code. */
+
+ cassette_toggle_output();
+}
diff --git a/src/devices/bus/a1bus/a1cassette.h b/src/devices/bus/a1bus/a1cassette.h
new file mode 100644
index 00000000000..e8d656c1c3a
--- /dev/null
+++ b/src/devices/bus/a1bus/a1cassette.h
@@ -0,0 +1,53 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ a1cassette.h
+
+ Apple I Cassette Interface
+
+*********************************************************************/
+
+#ifndef __A1BUS_CASSETTE__
+#define __A1BUS_CASSETTE__
+
+#include "a1bus.h"
+#include "imagedev/cassette.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class a1bus_cassette_device:
+ public device_t,
+ public device_a1bus_card_interface
+{
+public:
+ // construction/destruction
+ a1bus_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ a1bus_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ optional_device<cassette_image_device> m_cassette;
+
+ DECLARE_READ8_MEMBER(cassette_r);
+ DECLARE_WRITE8_MEMBER(cassette_w);
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+
+ void cassette_toggle_output();
+
+private:
+ UINT8 *m_rom;
+ int m_cassette_output_flipflop;
+};
+
+// device type definition
+extern const device_type A1BUS_CASSETTE;
+
+#endif /* __A1BUS_CASSETTE__ */
diff --git a/src/devices/bus/a1bus/a1cffa.c b/src/devices/bus/a1bus/a1cffa.c
new file mode 100644
index 00000000000..f67470bb5db
--- /dev/null
+++ b/src/devices/bus/a1bus/a1cffa.c
@@ -0,0 +1,156 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ a1cffa.c
+
+ Rich Dreher's Compact Flash for Apple I
+
+*********************************************************************/
+
+#include "a1cffa.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+#define CFFA_ROM_REGION "cffa_rom"
+#define CFFA_ATA_TAG "cffa_ata"
+
+const device_type A1BUS_CFFA = &device_creator<a1bus_cffa_device>;
+
+MACHINE_CONFIG_FRAGMENT( cffa )
+ MCFG_ATA_INTERFACE_ADD(CFFA_ATA_TAG, ata_devices, "hdd", NULL, false)
+MACHINE_CONFIG_END
+
+ROM_START( cffa )
+ ROM_REGION(0x2000, CFFA_ROM_REGION, 0)
+ ROM_LOAD ("cffaromv1.1.bin", 0x0000, 0x1fe0, CRC(bf6b55ad) SHA1(6a290be18485a06f243a3561c4e01be5aafa4bfe) )
+ROM_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor a1bus_cffa_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( cffa );
+}
+
+const rom_entry *a1bus_cffa_device::device_rom_region() const
+{
+ return ROM_NAME( cffa );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+a1bus_cffa_device::a1bus_cffa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, A1BUS_CFFA, "CFFA Compact Flash for Apple I", tag, owner, clock, "cffa1", __FILE__),
+ device_a1bus_card_interface(mconfig, *this),
+ m_ata(*this, CFFA_ATA_TAG)
+{
+}
+
+a1bus_cffa_device::a1bus_cffa_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_a1bus_card_interface(mconfig, *this),
+ m_ata(*this, CFFA_ATA_TAG)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a1bus_cffa_device::device_start()
+{
+ set_a1bus_device();
+
+ m_rom = device().machine().root_device().memregion(this->subtag(CFFA_ROM_REGION).c_str())->base();
+
+ install_device(0xafe0, 0xafff, read8_delegate(FUNC(a1bus_cffa_device::cffa_r), this), write8_delegate(FUNC(a1bus_cffa_device::cffa_w), this));
+ install_bank(0x9000, 0xafdf, 0, 0, (char *)"bank_cffa1", m_rom);
+
+ save_item(NAME(m_lastdata));
+ save_item(NAME(m_writeprotect));
+}
+
+void a1bus_cffa_device::device_reset()
+{
+ m_writeprotect = false;
+ m_lastdata = 0;
+}
+
+READ8_MEMBER(a1bus_cffa_device::cffa_r)
+{
+ switch (offset & 0xf)
+ {
+ case 0x0:
+ return m_lastdata>>8;
+
+ case 0x3:
+ m_writeprotect = false;
+ break;
+
+ case 0x4:
+ m_writeprotect = true;
+ break;
+
+ case 0x8:
+ m_lastdata = m_ata->read_cs0(space, (offset & 0xf) - 8, 0xff);
+ return m_lastdata & 0x00ff;
+
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ return m_ata->read_cs0(space, (offset & 0xf) - 8, 0xff);
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(a1bus_cffa_device::cffa_w)
+{
+ switch (offset & 0xf)
+ {
+ case 0x0:
+ m_lastdata &= 0x00ff;
+ m_lastdata |= data<<8;
+ break;
+
+ case 0x3:
+ m_writeprotect = false;
+ break;
+
+ case 0x4:
+ m_writeprotect = true;
+ break;
+
+
+ case 0x8:
+ m_ata->write_cs0(space, (offset & 0xf) - 8, data, 0xff);
+ break;
+
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ m_ata->write_cs0(space, (offset & 0xf) - 8, data, 0xff);
+ break;
+
+ }
+}
diff --git a/src/devices/bus/a1bus/a1cffa.h b/src/devices/bus/a1bus/a1cffa.h
new file mode 100644
index 00000000000..a1dc4258cbc
--- /dev/null
+++ b/src/devices/bus/a1bus/a1cffa.h
@@ -0,0 +1,53 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ a1cffa.h
+
+ Rich Dreher's Compact Flash for Apple I
+
+*********************************************************************/
+
+#ifndef __A1BUS_CFFA__
+#define __A1BUS_CFFA__
+
+#include "emu.h"
+#include "a1bus.h"
+#include "machine/ataintf.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class a1bus_cffa_device:
+ public device_t,
+ public device_a1bus_card_interface
+{
+public:
+ // construction/destruction
+ a1bus_cffa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ a1bus_cffa_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ required_device<ata_interface_device> m_ata;
+
+ DECLARE_READ8_MEMBER(cffa_r);
+ DECLARE_WRITE8_MEMBER(cffa_w);
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ UINT8 *m_rom;
+ UINT16 m_lastdata;
+ bool m_writeprotect;
+};
+
+// device type definition
+extern const device_type A1BUS_CFFA;
+
+#endif /* __A1BUS_CFFA__ */