summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/bus/coco
diff options
context:
space:
mode:
author Curt Coder <curtcoder@mail.com>2014-03-17 22:06:26 +0000
committer Curt Coder <curtcoder@mail.com>2014-03-17 22:06:26 +0000
commit4bba3f6e421184a50d035b33c04e7fef98160809 (patch)
treeec1ca778b330d7ce4c5a2c310e0eae8502e9e9d5 /src/emu/bus/coco
parentf3fe1ab6443027aef68590c7391b43dea0580c06 (diff)
(MESS) Moved the remaining slot interfaces to emu/bus. (nw)
Diffstat (limited to 'src/emu/bus/coco')
-rw-r--r--src/emu/bus/coco/coco_232.c90
-rw-r--r--src/emu/bus/coco/coco_232.h40
-rw-r--r--src/emu/bus/coco/coco_fdc.c672
-rw-r--r--src/emu/bus/coco/coco_fdc.h155
-rw-r--r--src/emu/bus/coco/coco_multi.c266
-rw-r--r--src/emu/bus/coco/coco_multi.h67
-rw-r--r--src/emu/bus/coco/coco_orch90.c83
-rw-r--r--src/emu/bus/coco/coco_orch90.h40
-rw-r--r--src/emu/bus/coco/coco_pak.c178
-rw-r--r--src/emu/bus/coco/coco_pak.h63
-rw-r--r--src/emu/bus/coco/cococart.c459
-rw-r--r--src/emu/bus/coco/cococart.h175
12 files changed, 2288 insertions, 0 deletions
diff --git a/src/emu/bus/coco/coco_232.c b/src/emu/bus/coco/coco_232.c
new file mode 100644
index 00000000000..14cc989f9cd
--- /dev/null
+++ b/src/emu/bus/coco/coco_232.c
@@ -0,0 +1,90 @@
+/***************************************************************************
+
+ coco_232.c
+
+ Code for emulating the CoCo RS-232 PAK
+
+***************************************************************************/
+
+#include "emu.h"
+#include "coco_232.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define UART_TAG "uart"
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static MACHINE_CONFIG_FRAGMENT(coco_rs232)
+ MCFG_DEVICE_ADD(UART_TAG, MOS6551, 0)
+ MCFG_MOS6551_XTAL(XTAL_1_8432MHz)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_232 = &device_creator<coco_232_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// coco_232_device - constructor
+//-------------------------------------------------
+
+coco_232_device::coco_232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, COCO_232, "CoCo RS-232 PAK", tag, owner, clock, "coco_232", __FILE__),
+ device_cococart_interface( mconfig, *this ),
+ m_uart(*this, UART_TAG)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_232_device::device_start()
+{
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor coco_232_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( coco_rs232 );
+}
+
+/*-------------------------------------------------
+ read
+-------------------------------------------------*/
+
+READ8_MEMBER(coco_232_device::read)
+{
+ UINT8 result = 0x00;
+
+ if ((offset >= 0x28) && (offset <= 0x2F))
+ result = m_uart->read(space, offset - 0x28);
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(coco_232_device::write)
+{
+ if ((offset >= 0x28) && (offset <= 0x2F))
+ m_uart->write(space, offset - 0x28, data);
+}
diff --git a/src/emu/bus/coco/coco_232.h b/src/emu/bus/coco/coco_232.h
new file mode 100644
index 00000000000..80d986a010c
--- /dev/null
+++ b/src/emu/bus/coco/coco_232.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#ifndef __COCO_232_H__
+#define __COCO_232_H__
+
+#include "emu.h"
+#include "cococart.h"
+#include "machine/mos6551.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> coco_232_device
+
+class coco_232_device :
+ public device_t,
+ public device_cococart_interface
+{
+public:
+ // construction/destruction
+ coco_232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+private:
+ // internal state
+ required_device<mos6551_device> m_uart;
+};
+
+
+// device type definition
+extern const device_type COCO_232;
+
+#endif /* __COCO_232_H__ */
diff --git a/src/emu/bus/coco/coco_fdc.c b/src/emu/bus/coco/coco_fdc.c
new file mode 100644
index 00000000000..d8e559c371a
--- /dev/null
+++ b/src/emu/bus/coco/coco_fdc.c
@@ -0,0 +1,672 @@
+/*********************************************************************
+
+ coco_fdc.c
+
+ CoCo/Dragon FDC
+
+ The CoCo and Dragon both use the Western Digital floppy disk controllers.
+ The CoCo uses either the WD1793 or the WD1773, the Dragon uses the WD2797,
+ which mostly uses the same command set with some subtle differences, most
+ notably the 2797 handles disk side select internally. The Dragon Alpha also
+ uses the WD2797, however as this is a built in interface and not an external
+ cartrige, it is dealt with in the main coco.c file.
+
+ The wd's variables are mapped to $FF48-$FF4B on the CoCo and on $FF40-$FF43
+ on the Dragon. In addition, there is another register
+ called DSKREG that controls the interface with the wd1793. DSKREG is
+ detailed below: But they appear to be
+
+ References:
+ CoCo: Disk Basic Unravelled
+ Dragon: Inferences from the PC-Dragon source code
+ DragonDos Controller, Disk and File Formats by Graham E Kinns
+
+ ---------------------------------------------------------------------------
+
+ DSKREG - the control register
+ CoCo ($FF40) Dragon ($FF48)
+
+ Bit Bit
+ 7 halt enable flag 7 not used
+ 6 drive select #3 6 not used
+ 5 density (0=single, 1=double) 5 NMI enable flag
+ and NMI enable flag
+ 4 write precompensation 4 write precompensation
+ 3 drive motor activation 3 single density enable
+ 2 drive select #2 2 drive motor activation
+ 1 drive select #1 1 drive select high bit
+ 0 drive select #0 0 drive select low bit
+
+ Reading from $FF48-$FF4F clears bit 7 of DSKREG ($FF40)
+
+ ---------------------------------------------------------------------------
+
+ 2007-02-22, P.Harvey-Smith
+
+ Began implementing the Dragon Delta Dos controler, this was actually the first
+ Dragon disk controler to market, beating Dragon Data's by a couple of months,
+ it is based around the WD2791 FDC, which is compatible with the WD1793/WD2797 used
+ by the standard CoCo and Dragon disk controlers except that it used an inverted
+ data bus, which is the reason the read/write handlers invert the data. This
+ controler like, the DragonDos WD2797 is mapped at $FF40-$FF43, in the normal
+ register order.
+
+ The Delta cart also has a register (74LS174 hex flipflop) at $FF44 encoded as
+ follows :-
+
+ Bit
+ 7 not used
+ 6 not used
+ 5 not used
+ 4 Single (0) / Double (1) density select
+ 3 5.25"(0) / 8"(1) Clock select
+ 2 Side select
+ 1 Drive select ms bit
+ 0 Drive select ls bit
+
+*********************************************************************/
+
+#include "emu.h"
+#include "coco_fdc.h"
+#include "imagedev/flopdrv.h"
+#include "includes/coco.h"
+#include "machine/wd17xx.h"
+#include "imagedev/flopdrv.h"
+#include "formats/coco_dsk.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define LOG_FDC 0
+#define WD_TAG "wd17xx"
+#define DISTO_TAG "disto"
+#define CLOUD9_TAG "cloud9"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+static const floppy_interface coco_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(coco),
+ "floppy_5_25",
+ NULL
+};
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+/*-------------------------------------------------
+ real_time_clock
+-------------------------------------------------*/
+
+coco_rtc_type_t coco_fdc_device::real_time_clock()
+{
+ coco_rtc_type_t result = (coco_rtc_type_t) machine().root_device().ioport("real_time_clock")->read_safe(RTC_NONE);
+
+ /* check to make sure we don't have any invalid values */
+ if (((result == RTC_DISTO) && (m_disto_msm6242 == NULL))
+ || ((result == RTC_CLOUD9) && (m_ds1315 == NULL)))
+ {
+ result = RTC_NONE;
+ }
+
+ return result;
+}
+/*-------------------------------------------------
+ fdc_intrq_w - callback from the FDC
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER( coco_fdc_device::fdc_intrq_w )
+{
+ set_intrq(state);
+ update_lines();
+}
+
+
+/*-------------------------------------------------
+ fdc_drq_w - callback from the FDC
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER( coco_fdc_device::fdc_drq_w )
+{
+ set_drq(state);
+ update_lines();
+}
+
+
+//**************************************************************************
+// COCO FDC
+//**************************************************************************
+
+static const wd17xx_interface coco_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, coco_fdc_device, fdc_intrq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, coco_fdc_device, fdc_drq_w),
+ {FLOPPY_0,FLOPPY_1,FLOPPY_2,FLOPPY_3}
+};
+
+static MACHINE_CONFIG_FRAGMENT(coco_fdc)
+ MCFG_WD1773_ADD(WD_TAG, coco_wd17xx_interface)
+ MCFG_DEVICE_ADD(DISTO_TAG, MSM6242, XTAL_32_768kHz)
+ MCFG_DS1315_ADD(CLOUD9_TAG)
+
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(coco_floppy_interface)
+MACHINE_CONFIG_END
+
+ROM_START( coco_fdc )
+ ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00)
+ ROM_LOAD_OPTIONAL( "disk10.rom", 0x0000, 0x2000, CRC(b4f9968e) SHA1(04115be3f97952b9d9310b52f806d04f80b40d03))
+ROM_END
+
+const device_type COCO_FDC = &device_creator<coco_fdc_device>;
+
+//-------------------------------------------------
+// coco_fdc_device - constructor
+//-------------------------------------------------
+coco_fdc_device::coco_fdc_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_cococart_interface( mconfig, *this )
+{
+}
+
+coco_fdc_device::coco_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, COCO_FDC, "CoCo FDC", tag, owner, clock, "coco_fdc", __FILE__),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_fdc_device::device_start()
+{
+ m_owner = dynamic_cast<cococart_slot_device *>(owner());
+ m_drq = 1;
+ m_disto_msm6242 = subdevice<msm6242_device>(DISTO_TAG);
+ m_ds1315 = subdevice<ds1315_device>(CLOUD9_TAG);
+ m_wd17xx = subdevice(WD_TAG);
+ m_dskreg = 0x00;
+ m_intrq = 0;
+ m_msm6242_rtc_address = 0;
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor coco_fdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( coco_fdc );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *coco_fdc_device::device_rom_region() const
+{
+ return ROM_NAME( coco_fdc );
+}
+
+/*-------------------------------------------------
+ get_cart_base
+-------------------------------------------------*/
+
+UINT8* coco_fdc_device::get_cart_base()
+{
+ return memregion("eprom")->base();
+}
+
+/*-------------------------------------------------
+ update_lines - CoCo specific disk
+ controller lines
+-------------------------------------------------*/
+
+void coco_fdc_device::update_lines()
+{
+ /* clear HALT enable under certain circumstances */
+ if ((m_intrq != 0) && (m_dskreg & 0x20))
+ m_dskreg &= ~0x80; /* clear halt enable */
+
+ /* set the NMI line */
+ m_owner->cart_set_line(COCOCART_LINE_NMI,
+ ((m_intrq != 0) && (m_dskreg & 0x20)) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR);
+
+ /* set the HALT line */
+ m_owner->cart_set_line(COCOCART_LINE_HALT,
+ ((m_drq == 0) && (m_dskreg & 0x80)) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR);
+}
+
+/*-------------------------------------------------
+ dskreg_w - function to write to CoCo
+ dskreg
+-------------------------------------------------*/
+
+void coco_fdc_device::dskreg_w(UINT8 data)
+{
+ UINT8 drive = 0;
+ UINT8 head = 0;
+
+ if (LOG_FDC)
+ {
+ logerror("fdc_coco_dskreg_w(): %c%c%c%c%c%c%c%c ($%02x)\n",
+ data & 0x80 ? 'H' : 'h',
+ data & 0x40 ? '3' : '.',
+ data & 0x20 ? 'D' : 'S',
+ data & 0x10 ? 'P' : 'p',
+ data & 0x08 ? 'M' : 'm',
+ data & 0x04 ? '2' : '.',
+ data & 0x02 ? '1' : '.',
+ data & 0x01 ? '0' : '.',
+ data);
+ }
+
+ /* An email from John Kowalski informed me that if the DS3 is
+ * high, and one of the other drive bits is selected (DS0-DS2), then the
+ * second side of DS0, DS1, or DS2 is selected. If multiple bits are
+ * selected in other situations, then both drives are selected, and any
+ * read signals get yucky.
+ */
+
+ if (data & 0x04)
+ drive = 2;
+ else if (data & 0x02)
+ drive = 1;
+ else if (data & 0x01)
+ drive = 0;
+ else if (data & 0x40)
+ drive = 3;
+
+ device_t *floppy[4];
+
+ floppy[0] = subdevice(FLOPPY_0);
+ floppy[1] = subdevice(FLOPPY_1);
+ floppy[2] = subdevice(FLOPPY_2);
+ floppy[3] = subdevice(FLOPPY_3);
+
+ for (int i = 0; i < 4; i++)
+ {
+ floppy_mon_w(floppy[i], i == drive ? CLEAR_LINE : ASSERT_LINE);
+ }
+
+ head = ((data & 0x40) && (drive != 3)) ? 1 : 0;
+
+ m_dskreg = data;
+
+ update_lines();
+
+ wd17xx_set_drive(m_wd17xx, drive);
+ wd17xx_set_side(m_wd17xx, head);
+ wd17xx_dden_w(m_wd17xx, !BIT(m_dskreg, 5));
+}
+
+/*-------------------------------------------------
+ read
+-------------------------------------------------*/
+
+READ8_MEMBER(coco_fdc_device::read)
+{
+ UINT8 result = 0;
+
+ switch(offset & 0xEF)
+ {
+ case 8:
+ result = wd17xx_status_r(m_wd17xx, space, 0);
+ break;
+ case 9:
+ result = wd17xx_track_r(m_wd17xx, space, 0);
+ break;
+ case 10:
+ result = wd17xx_sector_r(m_wd17xx, space, 0);
+ break;
+ case 11:
+ result = wd17xx_data_r(m_wd17xx, space, 0);
+ break;
+ }
+
+ /* other stuff for RTCs */
+ switch(offset)
+ {
+ case 0x10: /* FF50 */
+ if (real_time_clock() == RTC_DISTO)
+ result = m_disto_msm6242->read(space,m_msm6242_rtc_address);
+ break;
+
+ case 0x38: /* FF78 */
+ if (real_time_clock() == RTC_CLOUD9)
+ m_ds1315->read_0(space, offset);
+ break;
+
+ case 0x39: /* FF79 */
+ if (real_time_clock() == RTC_CLOUD9)
+ m_ds1315->read_1(space, offset);
+ break;
+
+ case 0x3C: /* FF7C */
+ if (real_time_clock() == RTC_CLOUD9)
+ result = m_ds1315->read_data(space, offset);
+ break;
+ }
+ return result;
+}
+
+
+
+/*-------------------------------------------------
+ write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(coco_fdc_device::write)
+{
+ switch(offset & 0x1F)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ dskreg_w(data);
+ break;
+ case 8:
+ wd17xx_command_w(m_wd17xx, space, 0, data);
+ break;
+ case 9:
+ wd17xx_track_w(m_wd17xx, space, 0, data);
+ break;
+ case 10:
+ wd17xx_sector_w(m_wd17xx, space, 0, data);
+ break;
+ case 11:
+ wd17xx_data_w(m_wd17xx, space, 0, data);
+ break;
+ };
+
+ /* other stuff for RTCs */
+ switch(offset)
+ {
+ case 0x10: /* FF50 */
+ if (real_time_clock() == RTC_DISTO)
+ m_disto_msm6242->write(space,m_msm6242_rtc_address, data);
+ break;
+
+ case 0x11: /* FF51 */
+ if (real_time_clock() == RTC_DISTO)
+ m_msm6242_rtc_address = data & 0x0f;
+ break;
+ }
+}
+
+
+//**************************************************************************
+// DRAGON FDC
+//**************************************************************************
+
+static MACHINE_CONFIG_FRAGMENT(dragon_fdc)
+ MCFG_WD2797_ADD(WD_TAG, coco_wd17xx_interface)
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(coco_floppy_interface)
+MACHINE_CONFIG_END
+
+
+ROM_START( dragon_fdc )
+ ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00)
+ ROM_LOAD_OPTIONAL( "ddos10.rom", 0x0000, 0x2000, CRC(b44536f6) SHA1(a8918c71d319237c1e3155bb38620acb114a80bc))
+ROM_END
+
+const device_type DRAGON_FDC = &device_creator<dragon_fdc_device>;
+
+//-------------------------------------------------
+// dragon_fdc_device - constructor
+//-------------------------------------------------
+dragon_fdc_device::dragon_fdc_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)
+ : coco_fdc_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+dragon_fdc_device::dragon_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : coco_fdc_device(mconfig, DRAGON_FDC, "Dragon FDC", tag, owner, clock, "dragon_fdc", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void dragon_fdc_device::device_start()
+{
+ m_owner = dynamic_cast<cococart_slot_device *>(owner());
+ m_drq = 0;
+ m_wd17xx = subdevice(WD_TAG);
+ m_dskreg = 0x00;
+ m_intrq = 0;
+ m_msm6242_rtc_address = 0;
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor dragon_fdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( dragon_fdc );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *dragon_fdc_device::device_rom_region() const
+{
+ return ROM_NAME( dragon_fdc );
+}
+
+
+
+/*-------------------------------------------------
+ update_lines - Dragon specific disk
+ controller lines
+-------------------------------------------------*/
+
+void dragon_fdc_device::update_lines()
+{
+ /* set the NMI line */
+ m_owner->cart_set_line(COCOCART_LINE_NMI,
+ ((m_intrq != 0) && (m_dskreg & 0x20)) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR);
+
+ /* set the CART line */
+ m_owner->cart_set_line(COCOCART_LINE_CART,
+ (m_drq != 0) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR);
+}
+
+
+/*-------------------------------------------------
+ dskreg_w - function to write to
+ Dragon dskreg
+-------------------------------------------------*/
+
+void dragon_fdc_device::dskreg_w(UINT8 data)
+{
+ if (LOG_FDC)
+ {
+ logerror("fdc_dragon_dskreg_w(): %c%c%c%c%c%c%c%c ($%02x)\n",
+ data & 0x80 ? 'X' : 'x',
+ data & 0x40 ? 'X' : 'x',
+ data & 0x20 ? 'N' : 'n',
+ data & 0x10 ? 'P' : 'p',
+ data & 0x08 ? 'S' : 'D',
+ data & 0x04 ? 'M' : 'm',
+ data & 0x02 ? '1' : '0',
+ data & 0x01 ? '1' : '0',
+ data);
+ }
+
+ if (data & 0x04)
+ wd17xx_set_drive(m_wd17xx, data & 0x03);
+
+ wd17xx_dden_w(m_wd17xx, BIT(data, 3));
+ m_dskreg = data;
+}
+
+
+
+/*-------------------------------------------------
+ read
+-------------------------------------------------*/
+
+READ8_MEMBER(dragon_fdc_device::read)
+{
+ UINT8 result = 0;
+ switch(offset & 0xEF)
+ {
+ case 0:
+ result = wd17xx_status_r(m_wd17xx, space, 0);
+ break;
+ case 1:
+ result = wd17xx_track_r(m_wd17xx, space, 0);
+ break;
+ case 2:
+ result = wd17xx_sector_r(m_wd17xx, space, 0);
+ break;
+ case 3:
+ result = wd17xx_data_r(m_wd17xx, space, 0);
+ break;
+ }
+ return result;
+}
+
+
+
+/*-------------------------------------------------
+ write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(dragon_fdc_device::write)
+{
+ switch(offset & 0xEF)
+ {
+ case 0:
+ wd17xx_command_w(m_wd17xx, space, 0, data);
+
+ /* disk head is encoded in the command byte */
+ /* Only for type 3 & 4 commands */
+ if (data & 0x80)
+ wd17xx_set_side(m_wd17xx, (data & 0x02) ? 1 : 0);
+ break;
+ case 1:
+ wd17xx_track_w(m_wd17xx, space, 0, data);
+ break;
+ case 2:
+ wd17xx_sector_w(m_wd17xx, space, 0, data);
+ break;
+ case 3:
+ wd17xx_data_w(m_wd17xx, space, 0, data);
+ break;
+ case 8: case 9: case 10: case 11:
+ case 12: case 13: case 14: case 15:
+ dskreg_w(data);
+ break;
+ };
+}
+
+//**************************************************************************
+// SDTANDY FDC
+//**************************************************************************
+
+ROM_START( sdtandy_fdc )
+ ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00)
+ ROM_LOAD_OPTIONAL( "sdtandy.rom", 0x0000, 0x2000, CRC(5d7779b7) SHA1(ca03942118f2deab2f6c8a89b8a4f41f2d0b94f1))
+ROM_END
+
+const device_type SDTANDY_FDC = &device_creator<sdtandy_fdc_device>;
+
+//-------------------------------------------------
+// sdtandy_fdc_device - constructor
+//-------------------------------------------------
+
+sdtandy_fdc_device::sdtandy_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : dragon_fdc_device(mconfig, SDTANDY_FDC, "SDTANDY FDC", tag, owner, clock, "sdtandy_fdc", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *sdtandy_fdc_device::device_rom_region() const
+{
+ return ROM_NAME( sdtandy_fdc );
+}
+
+//**************************************************************************
+// COCO FDC v1.1
+//**************************************************************************
+
+ROM_START( coco_fdc_v11 )
+ ROM_REGION(0x8000,"eprom",ROMREGION_ERASE00)
+ ROM_LOAD_OPTIONAL( "disk11.rom", 0x0000, 0x2000, CRC(0b9c5415) SHA1(10bdc5aa2d7d7f205f67b47b19003a4bd89defd1))
+ ROM_RELOAD(0x2000, 0x2000)
+ ROM_RELOAD(0x4000, 0x2000)
+ ROM_RELOAD(0x6000, 0x2000)
+ROM_END
+
+const device_type COCO_FDC_V11 = &device_creator<coco_fdc_v11_device>;
+
+//-------------------------------------------------
+// coco_fdc_v11_device - constructor
+//-------------------------------------------------
+
+coco_fdc_v11_device::coco_fdc_v11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : coco_fdc_device(mconfig, COCO_FDC_V11, "CoCo FDC v1.1", tag, owner, clock, "coco_fdc_v11", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *coco_fdc_v11_device::device_rom_region() const
+{
+ return ROM_NAME( coco_fdc_v11 );
+}
+
+//**************************************************************************
+// CP400 FDC
+//**************************************************************************
+
+ROM_START( cp400_fdc )
+ ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00)
+ ROM_LOAD("cp400dsk.rom", 0x0000, 0x2000, CRC(e9ad60a0) SHA1(827697fa5b755f5dc1efb054cdbbeb04e405405b))
+ROM_END
+
+const device_type CP400_FDC = &device_creator<cp400_fdc_device>;
+
+//-------------------------------------------------
+// cp400_fdc_device - constructor
+//-------------------------------------------------
+
+cp400_fdc_device::cp400_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : coco_fdc_device(mconfig, CP400_FDC, "CP400 FDC", tag, owner, clock, "cp400_fdc", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *cp400_fdc_device::device_rom_region() const
+{
+ return ROM_NAME( cp400_fdc );
+}
diff --git a/src/emu/bus/coco/coco_fdc.h b/src/emu/bus/coco/coco_fdc.h
new file mode 100644
index 00000000000..6e82ca4646d
--- /dev/null
+++ b/src/emu/bus/coco/coco_fdc.h
@@ -0,0 +1,155 @@
+#pragma once
+
+#ifndef __COCO_FDC_H__
+#define __COCO_FDC_H__
+
+#include "emu.h"
+#include "cococart.h"
+#include "machine/msm6242.h"
+#include "machine/ds1315.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> coco_rtc_type_t
+
+enum coco_rtc_type_t
+{
+ RTC_DISTO = 0x00,
+ RTC_CLOUD9 = 0x01,
+
+ RTC_NONE = 0xFF
+};
+
+// ======================> coco_fdc_device
+
+class coco_fdc_device :
+ public device_t,
+ public device_cococart_interface
+{
+public:
+ // construction/destruction
+ coco_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ coco_fdc_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;
+
+ virtual UINT8* get_cart_base();
+
+ virtual void update_lines();
+ virtual void dskreg_w(UINT8 data);
+
+ void set_intrq(UINT8 val) { m_intrq = val; }
+ void set_drq(UINT8 val) { m_drq = val; }
+
+ DECLARE_WRITE_LINE_MEMBER(fdc_intrq_w);
+ DECLARE_WRITE_LINE_MEMBER(fdc_drq_w);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ coco_rtc_type_t real_time_clock();
+
+ // internal state
+ cococart_slot_device *m_owner;
+
+ UINT8 m_dskreg;
+ UINT8 m_drq : 1;
+ UINT8 m_intrq : 1;
+
+ device_t *m_wd17xx; /* WD17xx */
+ ds1315_device *m_ds1315; /* DS1315 */
+
+ /* Disto RTC */
+ msm6242_device *m_disto_msm6242; /* 6242 RTC on Disto interface */
+ offs_t m_msm6242_rtc_address;
+};
+
+
+// device type definition
+extern const device_type COCO_FDC;
+
+// ======================> coco_fdc_v11_device
+
+class coco_fdc_v11_device :
+ public coco_fdc_device
+{
+public:
+ // construction/destruction
+ coco_fdc_v11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+};
+
+
+// device type definition
+extern const device_type COCO_FDC_V11;
+
+// ======================> cp400_fdc_device
+
+class cp400_fdc_device :
+ public coco_fdc_device
+{
+public:
+ // construction/destruction
+ cp400_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+};
+
+
+// device type definition
+extern const device_type CP400_FDC;
+
+// ======================> dragon_fdc_device
+
+class dragon_fdc_device :
+ public coco_fdc_device
+{
+public:
+ // construction/destruction
+ dragon_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ dragon_fdc_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;
+ virtual void update_lines();
+ virtual void dskreg_w(UINT8 data);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+private:
+};
+
+
+// device type definition
+extern const device_type DRAGON_FDC;
+
+// ======================> sdtandy_fdc_device
+
+class sdtandy_fdc_device :
+ public dragon_fdc_device
+{
+public:
+ // construction/destruction
+ sdtandy_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+};
+
+
+// device type definition
+extern const device_type SDTANDY_FDC;
+
+#endif /* __COCO_FDC_H__ */
diff --git a/src/emu/bus/coco/coco_multi.c b/src/emu/bus/coco/coco_multi.c
new file mode 100644
index 00000000000..0f71766b516
--- /dev/null
+++ b/src/emu/bus/coco/coco_multi.c
@@ -0,0 +1,266 @@
+/***************************************************************************
+
+ coco_multi.c
+
+ Code for emulating CoCo's Multi-Pak Interface
+
+ The Multi-Pak interface multiplexes all I/O lines from the Color
+ Computer's expansion port to four identical ports. All I/O lines
+ are continuously multiplexed except:
+
+ Pin 36 - *SCS
+ Pin 32 - *CTS
+ Pin 8 - *CART
+
+ These I/O lines are switched in one of two ways. First, is the front
+ panel, four position switch. When adjusted the switch will direct the
+ MPI to target these three I/O lines to the selected slot.
+
+ Second, the MPI will listen to writes to 0xff7f and respond accordingly:
+
+ bit 0 --\___ Target *SCS to this slot number
+ bit 1 --/
+ bit 2 ------ Ignore
+ bit 3 ------ Ignore
+ bit 4 --\___ Target *CTS and *CART to this slot number
+ bit 5 --/
+ bit 6 ------ Ignore
+ bit 7 ------ Ignore
+
+ After writing to 0xff7f, the position of the physical switch has no
+ effect until reset.
+
+ Reading is supported on 0xff7f. It will reflect the position of the
+ physical switch. Until data is written to 0xff7f, then it will only
+ reflect what has been written until a reset.
+
+ A common modification users of the OS-9 operating system made was to
+ tie all of the *CART pins together on the MPI motherboard. The *CART
+ line is connected to the 6809's IRQ line. This allowed any hardware
+ device in any slot to signal an IRQ to the CPU, no matter what the
+ switch position was. OS-9 was designed from the very start to poll
+ each device attached on every IRQ signal.
+
+ Because of sloppy address decoding the original MPI also responds to
+ $FF9F. No software is known to take advantage of this. After the
+ introduction of the CoCo 3, which uses $FF9F internally, Tandy provided
+ free upgrades to any MPI to fix this problem.
+
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/coco.h"
+#include "coco_multi.h"
+#include "coco_232.h"
+#include "coco_orch90.h"
+#include "coco_pak.h"
+#include "coco_fdc.h"
+
+#define SLOT1_TAG "slot1"
+#define SLOT2_TAG "slot2"
+#define SLOT3_TAG "slot3"
+#define SLOT4_TAG "slot4"
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static SLOT_INTERFACE_START(coco_cart_slot1_3)
+ SLOT_INTERFACE("rs232", COCO_232)
+ SLOT_INTERFACE("orch90", COCO_ORCH90)
+ SLOT_INTERFACE("banked_16k", COCO_PAK_BANKED)
+ SLOT_INTERFACE("pak", COCO_PAK)
+SLOT_INTERFACE_END
+static SLOT_INTERFACE_START(coco_cart_slot4)
+ SLOT_INTERFACE("fdcv11", COCO_FDC_V11)
+ SLOT_INTERFACE("rs232", COCO_232)
+ SLOT_INTERFACE("orch90", COCO_ORCH90)
+ SLOT_INTERFACE("banked_16k", COCO_PAK_BANKED)
+ SLOT_INTERFACE("pak", COCO_PAK)
+SLOT_INTERFACE_END
+
+WRITE_LINE_MEMBER(coco_multipak_device::multi_cart_w)
+{
+ cococart_slot_device *cart = dynamic_cast<cococart_slot_device *>(owner());
+ cart->m_cart_callback.writeline(this,state);
+}
+
+WRITE_LINE_MEMBER(coco_multipak_device::multi_nmi_w)
+{
+ cococart_slot_device *cart = dynamic_cast<cococart_slot_device *>(owner());
+ cart->m_nmi_callback.writeline(this,state);
+}
+
+WRITE_LINE_MEMBER(coco_multipak_device::multi_halt_w)
+{
+ cococart_slot_device *cart = dynamic_cast<cococart_slot_device *>(owner());
+ cart->m_halt_callback.writeline(this,state);
+}
+
+static const cococart_interface multi_cococart_interface =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, coco_multipak_device, multi_cart_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, coco_multipak_device, multi_nmi_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, coco_multipak_device, multi_halt_w)
+};
+
+static MACHINE_CONFIG_FRAGMENT(coco_multi)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT1_TAG, multi_cococart_interface, coco_cart_slot1_3, NULL)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT2_TAG, multi_cococart_interface, coco_cart_slot1_3, NULL)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT3_TAG, multi_cococart_interface, coco_cart_slot1_3, NULL)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT4_TAG, multi_cococart_interface, coco_cart_slot4, "fdcv11")
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_MULTIPAK = &device_creator<coco_multipak_device>;
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// coco_multipak_device - constructor
+//-------------------------------------------------
+
+coco_multipak_device::coco_multipak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, COCO_MULTIPAK, "CoCo Multi-Pak Interface", tag, owner, clock, "coco_multipak", __FILE__),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_multipak_device::device_start()
+{
+ // identify slots
+ m_slots[0] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT1_TAG));
+ m_slots[1] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT2_TAG));
+ m_slots[2] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT3_TAG));
+ m_slots[3] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT4_TAG));
+ m_owner = dynamic_cast<cococart_slot_device *>(owner());
+
+ // install $FF7F handler
+ write8_delegate wh = write8_delegate(FUNC(coco_multipak_device::ff7f_write), this);
+ machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM).install_write_handler(0xFF7F, 0xFF7F, wh);
+
+ // initial state
+ m_select = 0xFF;
+
+ // save state
+ save_item(NAME(m_select));
+}
+
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void coco_multipak_device::device_reset()
+{
+ m_select = 0xFF;
+}
+
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor coco_multipak_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( coco_multi );
+}
+
+
+
+//-------------------------------------------------
+// get_cart_base
+//-------------------------------------------------
+
+UINT8* coco_multipak_device::get_cart_base()
+{
+ return active_cts_slot()->get_cart_base();
+}
+
+
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+READ8_MEMBER(coco_multipak_device::read)
+{
+ return active_scs_slot()->read(space,offset);
+}
+
+
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+WRITE8_MEMBER(coco_multipak_device::write)
+{
+ active_scs_slot()->write(space,offset,data);
+}
+
+
+
+//-------------------------------------------------
+// ff7f_write
+//-------------------------------------------------
+
+WRITE8_MEMBER(coco_multipak_device::ff7f_write)
+{
+ set_select(data);
+}
+
+
+
+//-------------------------------------------------
+// set_select
+//-------------------------------------------------
+
+void coco_multipak_device::set_select(UINT8 new_select)
+{
+ UINT8 xorval = m_select ^ new_select;
+ m_select = new_select;
+ if (xorval & 0x30)
+ cart_base_changed();
+}
+
+
+
+//-------------------------------------------------
+// active_scs_slot
+//-------------------------------------------------
+
+cococart_slot_device *coco_multipak_device::active_scs_slot(void)
+{
+ return m_slots[(m_select >> 0) & 0x03];
+}
+
+
+
+//-------------------------------------------------
+// active_cts_slot
+//-------------------------------------------------
+
+cococart_slot_device *coco_multipak_device::active_cts_slot(void)
+{
+ return m_slots[(m_select >> 4) & 0x03];
+}
diff --git a/src/emu/bus/coco/coco_multi.h b/src/emu/bus/coco/coco_multi.h
new file mode 100644
index 00000000000..f16ebe7cc5d
--- /dev/null
+++ b/src/emu/bus/coco/coco_multi.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+
+ coco_multi.h
+
+ Multi-Pak interface emulation
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __COCO_MULTI_H__
+#define __COCO_MULTI_H__
+
+#include "emu.h"
+#include "cococart.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> coco_multipak_device
+
+class coco_multipak_device :
+ public device_t,
+ public device_cococart_interface
+{
+public:
+ // construction/destruction
+ coco_multipak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual UINT8* get_cart_base();
+
+ DECLARE_WRITE_LINE_MEMBER(multi_cart_w);
+ DECLARE_WRITE_LINE_MEMBER(multi_nmi_w);
+ DECLARE_WRITE_LINE_MEMBER(multi_halt_w);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+private:
+ // device references
+ cococart_slot_device *m_owner;
+ cococart_slot_device *m_slots[4];
+
+ // internal state
+ UINT8 m_select;
+
+ // methods
+ DECLARE_WRITE8_MEMBER(ff7f_write);
+ cococart_slot_device *active_scs_slot(void);
+ cococart_slot_device *active_cts_slot(void);
+ void set_select(UINT8 new_select);
+};
+
+
+// device type definition
+extern const device_type COCO_MULTIPAK;
+
+#endif /* __COCO_MULTI_H__ */
diff --git a/src/emu/bus/coco/coco_orch90.c b/src/emu/bus/coco/coco_orch90.c
new file mode 100644
index 00000000000..ba1aa29cf69
--- /dev/null
+++ b/src/emu/bus/coco/coco_orch90.c
@@ -0,0 +1,83 @@
+/***************************************************************************
+
+ orch90.c
+
+ Code for emulating the CoCo Orch-90 (Orchestra 90) sound cartridge
+
+ The Orch-90 was a simple sound cartridge; it had two 8-bit DACs
+ supporting stereo sound. The left channel was at $FF7A, and the right
+ channel was at $FF7B
+
+***************************************************************************/
+
+#include "emu.h"
+#include "coco_orch90.h"
+#include "sound/dac.h"
+
+static MACHINE_CONFIG_FRAGMENT(coco_orch90)
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SOUND_ADD("dac_left", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ADD("dac_right", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_ORCH90 = &device_creator<coco_orch90_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// coco_orch90_device - constructor
+//-------------------------------------------------
+
+coco_orch90_device::coco_orch90_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, COCO_ORCH90, "CoCo Orch-90 PAK", tag, owner, clock, "coco_orch90", __FILE__),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_orch90_device::device_start()
+{
+ m_left_dac = subdevice<dac_device>("dac_left");
+ m_right_dac = subdevice<dac_device>("dac_right");
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor coco_orch90_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( coco_orch90 );
+}
+
+/*-------------------------------------------------
+ write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(coco_orch90_device::write)
+{
+ switch(offset)
+ {
+ case 0x3A:
+ /* left channel write */
+ m_left_dac->write_unsigned8(data);
+ break;
+
+ case 0x3B:
+ /* right channel write */
+ m_right_dac->write_unsigned8(data);
+ break;
+ }
+}
diff --git a/src/emu/bus/coco/coco_orch90.h b/src/emu/bus/coco/coco_orch90.h
new file mode 100644
index 00000000000..b7e27f43f32
--- /dev/null
+++ b/src/emu/bus/coco/coco_orch90.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#ifndef __COCO_ORCH90_H__
+#define __COCO_ORCH90_H__
+
+#include "emu.h"
+#include "sound/dac.h"
+#include "cococart.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> coco_orch90_device
+
+class coco_orch90_device :
+ public device_t,
+ public device_cococart_interface
+{
+public:
+ // construction/destruction
+ coco_orch90_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write);
+private:
+ // internal state
+ dac_device *m_left_dac;
+ dac_device *m_right_dac;
+};
+
+
+// device type definition
+extern const device_type COCO_ORCH90;
+
+#endif /* __COCO_ORCH90_H__ */
diff --git a/src/emu/bus/coco/coco_pak.c b/src/emu/bus/coco/coco_pak.c
new file mode 100644
index 00000000000..f106d7617cc
--- /dev/null
+++ b/src/emu/bus/coco/coco_pak.c
@@ -0,0 +1,178 @@
+/***************************************************************************
+
+ coco_pak.c
+
+ Code for emulating standard CoCo cartridges
+
+***************************************************************************/
+
+#include "emu.h"
+#include "coco_pak.h"
+#include "includes/coco.h"
+#include "imagedev/cartslot.h"
+
+#define CARTSLOT_TAG "cart"
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static MACHINE_CONFIG_FRAGMENT(coco_pak)
+MACHINE_CONFIG_END
+
+ROM_START( coco_pak )
+ ROM_REGION(0x8000,CARTSLOT_TAG,ROMREGION_ERASE00)
+ ROM_CART_LOAD(CARTSLOT_TAG, 0x0000, 0x8000, ROM_OPTIONAL | ROM_MIRROR)
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_PAK = &device_creator<coco_pak_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// coco_pak_device - constructor
+//-------------------------------------------------
+coco_pak_device::coco_pak_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_cococart_interface( mconfig, *this )
+{
+}
+
+coco_pak_device::coco_pak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, COCO_PAK, "CoCo Program PAK", tag, owner, clock, "cocopak", __FILE__),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_pak_device::device_start()
+{
+ m_cart = dynamic_cast<device_image_interface *>(owner());
+ m_owner = dynamic_cast<cococart_slot_device *>(owner());
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor coco_pak_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( coco_pak );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *coco_pak_device::device_rom_region() const
+{
+ return ROM_NAME( coco_pak );
+}
+
+/*-------------------------------------------------
+ device_reset - device-specific startup
+-------------------------------------------------*/
+
+void coco_pak_device::device_reset()
+{
+ if (m_cart->exists()) {
+ cococart_line_value cart_line;
+
+ cart_line = machine().root_device().ioport(CART_AUTOSTART_TAG)->read_safe(0x01)
+ ? COCOCART_LINE_VALUE_Q
+ : COCOCART_LINE_VALUE_CLEAR;
+
+ /* normal CoCo PAKs tie their CART line to Q - the system clock */
+ m_owner->cart_set_line(COCOCART_LINE_CART,cart_line);
+ }
+}
+
+/*-------------------------------------------------
+ get_cart_base
+-------------------------------------------------*/
+
+UINT8* coco_pak_device::get_cart_base()
+{
+ return memregion(CARTSLOT_TAG)->base();
+}
+
+/***************************************************************************
+ BANKED CARTRIDGES
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_PAK_BANKED = &device_creator<coco_pak_banked_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// coco_pak_device - constructor
+//-------------------------------------------------
+
+coco_pak_banked_device::coco_pak_banked_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : coco_pak_device(mconfig, COCO_PAK_BANKED, "CoCo Program PAK (Banked)", tag, owner, clock, "cocopak_banked", __FILE__)
+{
+}
+
+/*-------------------------------------------------
+ device_reset - device-specific startup
+-------------------------------------------------*/
+
+void coco_pak_banked_device::device_reset()
+{
+ coco_pak_device::device_reset();
+
+ banked_pak_set_bank(0);
+}
+
+/*-------------------------------------------------
+ banked_pak_set_bank - function to set the bank
+-------------------------------------------------*/
+
+void coco_pak_banked_device::banked_pak_set_bank(UINT32 bank)
+{
+ UINT64 pos;
+ UINT32 i;
+ UINT8 *rom = memregion(CARTSLOT_TAG)->base();
+ UINT32 rom_length = memregion(CARTSLOT_TAG)->bytes();
+
+ if (m_cart->exists()) {
+ pos = (bank * 0x4000) % m_cart->length();
+
+ for (i = 0; i < rom_length / 0x4000; i++)
+ {
+ m_cart->fseek(pos, SEEK_SET);
+ m_cart->fread(&rom[i * 0x4000], 0x4000);
+ }
+ }
+}
+
+/*-------------------------------------------------
+ write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(coco_pak_banked_device::write)
+{
+ switch(offset)
+ {
+ case 0:
+ /* set the bank */
+ banked_pak_set_bank(data);
+ break;
+ }
+}
diff --git a/src/emu/bus/coco/coco_pak.h b/src/emu/bus/coco/coco_pak.h
new file mode 100644
index 00000000000..67f580f6daf
--- /dev/null
+++ b/src/emu/bus/coco/coco_pak.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#ifndef __COCO_PAK_H__
+#define __COCO_PAK_H__
+
+#include "emu.h"
+#include "cococart.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> coco_pak_device
+
+class coco_pak_device :
+ public device_t,
+ public device_cococart_interface
+{
+public:
+ // construction/destruction
+ coco_pak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ coco_pak_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;
+
+ virtual UINT8* get_cart_base();
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // internal state
+ device_image_interface *m_cart;
+ cococart_slot_device *m_owner;
+};
+
+
+// device type definition
+extern const device_type COCO_PAK;
+
+// ======================> coco_pak_banked_device
+
+class coco_pak_banked_device :
+ public coco_pak_device
+{
+public:
+ // construction/destruction
+ coco_pak_banked_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ // device-level overrides
+ virtual void device_reset();
+ virtual DECLARE_WRITE8_MEMBER(write);
+private:
+ void banked_pak_set_bank(UINT32 bank);
+};
+
+
+// device type definition
+extern const device_type COCO_PAK_BANKED;
+#endif /* __COCO_PAK_H__ */
diff --git a/src/emu/bus/coco/cococart.c b/src/emu/bus/coco/cococart.c
new file mode 100644
index 00000000000..85c8844e0e0
--- /dev/null
+++ b/src/emu/bus/coco/cococart.c
@@ -0,0 +1,459 @@
+/*********************************************************************
+
+ cococart.c
+
+ CoCo/Dragon cartridge management
+
+*********************************************************************/
+
+#include "emu.h"
+#include "cococart.h"
+#include "emuopts.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define LOG_LINE 0
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCOCART_SLOT = &device_creator<cococart_slot_device>;
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// cococart_slot_device - constructor
+//-------------------------------------------------
+cococart_slot_device::cococart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, COCOCART_SLOT, "CoCo Cartridge Slot", tag, owner, clock, "cococart_slot", __FILE__),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cococart_slot_device::device_start()
+{
+ for(int i=0; i<TIMER_POOL; i++ )
+ {
+ m_cart_line.timer[i] = timer_alloc(TIMER_CART);
+ m_nmi_line.timer[i] = timer_alloc(TIMER_NMI);
+ m_halt_line.timer[i] = timer_alloc(TIMER_HALT);
+ }
+
+ m_cart_line.timer_index = 0;
+ m_cart_line.delay = 0;
+ m_cart_line.value = COCOCART_LINE_VALUE_CLEAR;
+ m_cart_line.line = 0;
+ m_cart_line.q_count = 0;
+ m_cart_line.callback.resolve(m_cart_callback, *this);
+
+ m_nmi_line.timer_index = 0;
+ /* 12 allowed one more instruction to finished after the line is pulled */
+ m_nmi_line.delay = 12;
+ m_nmi_line.value = COCOCART_LINE_VALUE_CLEAR;
+ m_nmi_line.line = 0;
+ m_nmi_line.q_count = 0;
+ m_nmi_line.callback.resolve(m_nmi_callback, *this);
+
+ m_halt_line.timer_index = 0;
+ /* 6 allowed one more instruction to finished after the line is pulled */
+ m_halt_line.delay = 6;
+ m_halt_line.value = COCOCART_LINE_VALUE_CLEAR;
+ m_halt_line.line = 0;
+ m_halt_line.q_count = 0;
+ m_halt_line.callback.resolve(m_halt_callback, *this);
+
+ m_cart = dynamic_cast<device_cococart_interface *>(get_card_device());
+}
+
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cococart_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const cococart_interface *intf = reinterpret_cast<const cococart_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<cococart_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_cart_callback, 0, sizeof(m_cart_callback));
+ memset(&m_nmi_callback, 0, sizeof(m_nmi_callback));
+ memset(&m_halt_callback, 0, sizeof(m_halt_callback));
+ }
+
+ // set brief and instance name
+ update_names();
+}
+
+
+
+//-------------------------------------------------
+// device_timer - handle timer callbacks
+//-------------------------------------------------
+
+void cococart_slot_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_CART:
+ set_line("CART", m_cart_line, (cococart_line_value) param);
+ break;
+
+ case TIMER_NMI:
+ set_line("NMI", m_nmi_line, (cococart_line_value) param);
+ break;
+
+ case TIMER_HALT:
+ set_line("HALT", m_halt_line, (cococart_line_value) param);
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// coco_cartridge_r
+//-------------------------------------------------
+
+READ8_MEMBER(cococart_slot_device::read)
+{
+ UINT8 result = 0x00;
+ if (m_cart)
+ result = m_cart->read(space, offset);
+ return result;
+}
+
+
+//-------------------------------------------------
+// coco_cartridge_w
+//-------------------------------------------------
+
+WRITE8_MEMBER(cococart_slot_device::write)
+{
+ if (m_cart)
+ m_cart->write(space, offset, data);
+}
+
+
+
+//-------------------------------------------------
+// line_value_string
+//-------------------------------------------------
+
+static const char *line_value_string(cococart_line_value value)
+{
+ const char *s = NULL;
+ switch(value)
+ {
+ case COCOCART_LINE_VALUE_CLEAR:
+ s = "CLEAR";
+ break;
+ case COCOCART_LINE_VALUE_ASSERT:
+ s = "ASSERT";
+ break;
+ case COCOCART_LINE_VALUE_Q:
+ s = "Q";
+ break;
+ default:
+ fatalerror("Invalid value\n");
+ break;
+ }
+ return s;
+}
+
+
+
+//-------------------------------------------------
+// set_line
+//-------------------------------------------------
+
+void cococart_slot_device::set_line(const char *line_name, coco_cartridge_line &line, cococart_line_value value)
+{
+ if ((line.value != value) || (value == COCOCART_LINE_VALUE_Q))
+ {
+ line.value = value;
+
+ if (LOG_LINE)
+ logerror("[%s]: set_line(): %s <= %s\n", machine().describe_context(), line_name, line_value_string(value));
+ /* engage in a bit of gymnastics for this odious 'Q' value */
+ switch(line.value)
+ {
+ case COCOCART_LINE_VALUE_CLEAR:
+ line.line = 0x00;
+ line.q_count = 0;
+ break;
+
+ case COCOCART_LINE_VALUE_ASSERT:
+ line.line = 0x01;
+ line.q_count = 0;
+ break;
+
+ case COCOCART_LINE_VALUE_Q:
+ line.line = line.line ? 0x00 : 0x01;
+ if (line.q_count++ < 4)
+ set_line_timer(line, value);
+ break;
+ }
+
+ /* invoke the callback, if present */
+ if (!line.callback.isnull())
+ line.callback(line.line);
+ }
+}
+
+
+
+//-------------------------------------------------
+// set_line_timer()
+//-------------------------------------------------
+
+void cococart_slot_device::set_line_timer(coco_cartridge_line &line, cococart_line_value value)
+{
+ /* calculate delay; delay dependant on cycles per second */
+ attotime delay = (line.delay != 0)
+ ? machine().firstcpu->cycles_to_attotime(line.delay)
+ : attotime::zero;
+
+ line.timer[line.timer_index]->adjust(delay, (int) value);
+ line.timer_index = (line.timer_index + 1) % TIMER_POOL;
+}
+
+
+
+//-------------------------------------------------
+// twiddle_line_if_q
+//-------------------------------------------------
+
+void cococart_slot_device::twiddle_line_if_q(coco_cartridge_line &line)
+{
+ if (line.value == COCOCART_LINE_VALUE_Q)
+ {
+ line.q_count = 0;
+ set_line_timer(line, COCOCART_LINE_VALUE_Q);
+ }
+}
+
+
+
+//-------------------------------------------------
+// coco_cartridge_twiddle_q_lines - hack to
+// support twiddling the Q line
+//-------------------------------------------------
+
+void cococart_slot_device::twiddle_q_lines()
+{
+ twiddle_line_if_q(m_cart_line);
+ twiddle_line_if_q(m_nmi_line);
+ twiddle_line_if_q(m_halt_line);
+}
+
+
+//-------------------------------------------------
+// coco_cartridge_set_line
+//-------------------------------------------------
+
+void cococart_slot_device::cart_set_line(cococart_line line, cococart_line_value value)
+{
+ switch (line)
+ {
+ case COCOCART_LINE_CART:
+ set_line_timer(m_cart_line, value);
+ break;
+
+ case COCOCART_LINE_NMI:
+ set_line_timer(m_nmi_line, value);
+ break;
+
+ case COCOCART_LINE_HALT:
+ set_line_timer(m_halt_line, value);
+ break;
+
+ case COCOCART_LINE_SOUND_ENABLE:
+ // do nothing for now
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// get_cart_base
+//-------------------------------------------------
+
+UINT8* cococart_slot_device::get_cart_base()
+{
+ if (m_cart != NULL)
+ return m_cart->get_cart_base();
+ return NULL;
+}
+
+
+
+//-------------------------------------------------
+// set_cart_base_update
+//-------------------------------------------------
+
+void cococart_slot_device::set_cart_base_update(cococart_base_update_delegate update)
+{
+ if (m_cart != NULL)
+ m_cart->set_cart_base_update(update);
+}
+
+
+
+//-------------------------------------------------
+// call_load
+//-------------------------------------------------
+
+bool cococart_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ offs_t read_length = 0;
+ if (software_entry() == NULL)
+ {
+ read_length = fread(m_cart->get_cart_base(), 0x8000);
+ }
+ else
+ {
+ read_length = get_software_region_length("rom");
+ memcpy(m_cart->get_cart_base(), get_software_region("rom"), read_length);
+ }
+ while(read_length < 0x8000)
+ {
+ offs_t len = MIN(read_length, 0x8000 - read_length);
+ memcpy(m_cart->get_cart_base() + read_length, m_cart->get_cart_base(), len);
+ read_length += len;
+ }
+ }
+ return IMAGE_INIT_PASS;
+}
+
+
+
+//-------------------------------------------------
+// call_softlist_load
+//-------------------------------------------------
+
+bool cococart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry)
+{
+ load_software_part_region(*this, swlist, swname, start_entry );
+ return TRUE;
+}
+
+
+
+//-------------------------------------------------
+// get_default_card_software
+//-------------------------------------------------
+
+void cococart_slot_device::get_default_card_software(astring &result)
+{
+ software_get_default_slot(result, "pak");
+}
+
+
+
+
+//**************************************************************************
+// DEVICE COCO CART INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_cococart_interface - constructor
+//-------------------------------------------------
+
+device_cococart_interface::device_cococart_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device)
+{
+}
+
+
+
+//-------------------------------------------------
+// ~device_cococart_interface - destructor
+//-------------------------------------------------
+
+device_cococart_interface::~device_cococart_interface()
+{
+}
+
+
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+READ8_MEMBER(device_cococart_interface::read)
+{
+ return 0x00;
+}
+
+
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+WRITE8_MEMBER(device_cococart_interface::write)
+{
+}
+
+
+
+//-------------------------------------------------
+// get_cart_base
+//-------------------------------------------------
+
+UINT8* device_cococart_interface::get_cart_base()
+{
+ return NULL;
+}
+
+
+
+//-------------------------------------------------
+// set_cart_base_update
+//-------------------------------------------------
+
+void device_cococart_interface::set_cart_base_update(cococart_base_update_delegate update)
+{
+ m_update = update;
+}
+
+
+
+//-------------------------------------------------
+// cart_base_changed
+//-------------------------------------------------
+
+void device_cococart_interface::cart_base_changed(void)
+{
+ if (!m_update.isnull())
+ m_update(get_cart_base());
+}
diff --git a/src/emu/bus/coco/cococart.h b/src/emu/bus/coco/cococart.h
new file mode 100644
index 00000000000..e207ae26068
--- /dev/null
+++ b/src/emu/bus/coco/cococart.h
@@ -0,0 +1,175 @@
+/*********************************************************************
+
+ cococart.h
+
+ CoCo/Dragon cartridge management
+
+*********************************************************************/
+
+#ifndef __COCOCART_H__
+#define __COCOCART_H__
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* TIMER_POOL: Must be power of two */
+#define TIMER_POOL 2
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* output lines on the CoCo cartridge slot */
+enum cococart_line
+{
+ COCOCART_LINE_CART, /* connects to PIA1 CB1 */
+ COCOCART_LINE_NMI, /* connects to NMI line on CPU */
+ COCOCART_LINE_HALT, /* connects to HALT line on CPU */
+ COCOCART_LINE_SOUND_ENABLE /* sound enable */
+};
+
+/* since we have a special value "Q" - we have to use a special enum here */
+enum cococart_line_value
+{
+ COCOCART_LINE_VALUE_CLEAR,
+ COCOCART_LINE_VALUE_ASSERT,
+ COCOCART_LINE_VALUE_Q
+};
+
+struct coco_cartridge_line
+{
+ emu_timer *timer[TIMER_POOL];
+ int timer_index;
+ int delay;
+ cococart_line_value value;
+ int line;
+ int q_count;
+ devcb_resolved_write_line callback;
+};
+
+// ======================> cococart_interface
+
+struct cococart_interface
+{
+ devcb_write_line m_cart_callback;
+ devcb_write_line m_nmi_callback;
+ devcb_write_line m_halt_callback;
+};
+
+// ======================> cococart_base_update_delegate
+
+// direct region update handler
+typedef delegate<void (UINT8 *)> cococart_base_update_delegate;
+
+
+// ======================> cococart_slot_device
+class device_cococart_interface;
+
+class cococart_slot_device : public device_t,
+ public cococart_interface,
+ public device_slot_interface,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ cococart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry);
+
+ virtual iodevice_t image_type() const { return IO_CARTSLOT; }
+
+ virtual bool is_readable() const { return 1; }
+ virtual bool is_writeable() const { return 0; }
+ virtual bool is_creatable() const { return 0; }
+ virtual bool must_be_loaded() const { return 0; }
+ virtual bool is_reset_on_load() const { return 1; }
+ virtual const char *image_interface() const { return "coco_cart"; }
+ virtual const char *file_extensions() const { return "ccc,rom"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+
+ // slot interface overrides
+ virtual void get_default_card_software(astring &result);
+
+ // reading and writing to $FF40-$FF7F
+ DECLARE_READ8_MEMBER(read);
+ DECLARE_WRITE8_MEMBER(write);
+
+ // sets a cartridge line
+ void cart_set_line(cococart_line line, cococart_line_value value);
+
+ // hack to support twiddling the Q line
+ void twiddle_q_lines();
+
+ // cart base
+ UINT8* get_cart_base();
+ void set_cart_base_update(cococart_base_update_delegate update);
+
+private:
+ enum
+ {
+ TIMER_CART,
+ TIMER_NMI,
+ TIMER_HALT
+ };
+
+ // configuration
+ coco_cartridge_line m_cart_line;
+ coco_cartridge_line m_nmi_line;
+ coco_cartridge_line m_halt_line;
+
+ // cartridge
+ device_cococart_interface *m_cart;
+
+ // methods
+ void set_line(const char *line_name, coco_cartridge_line &line, cococart_line_value value);
+ void set_line_timer(coco_cartridge_line &line, cococart_line_value value);
+ void twiddle_line_if_q(coco_cartridge_line &line);
+};
+
+// device type definition
+extern const device_type COCOCART_SLOT;
+
+// ======================> device_cococart_interface
+
+class device_cococart_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_cococart_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_cococart_interface();
+
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+ virtual UINT8* get_cart_base();
+ void set_cart_base_update(cococart_base_update_delegate update);
+
+protected:
+ void cart_base_changed(void);
+
+private:
+ cococart_base_update_delegate m_update;
+};
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_COCO_CARTRIDGE_ADD(_tag,_config,_slot_intf,_def_slot) \
+ MCFG_DEVICE_ADD(_tag, COCOCART_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
+
+#define MCFG_COCO_CARTRIDGE_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#endif /* __COCOCART_H__ */