diff options
author | 2014-03-17 22:06:26 +0000 | |
---|---|---|
committer | 2014-03-17 22:06:26 +0000 | |
commit | 4bba3f6e421184a50d035b33c04e7fef98160809 (patch) | |
tree | ec1ca778b330d7ce4c5a2c310e0eae8502e9e9d5 /src/emu/bus/coco | |
parent | f3fe1ab6443027aef68590c7391b43dea0580c06 (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.c | 90 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_232.h | 40 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_fdc.c | 672 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_fdc.h | 155 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_multi.c | 266 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_multi.h | 67 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_orch90.c | 83 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_orch90.h | 40 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_pak.c | 178 | ||||
-rw-r--r-- | src/emu/bus/coco/coco_pak.h | 63 | ||||
-rw-r--r-- | src/emu/bus/coco/cococart.c | 459 | ||||
-rw-r--r-- | src/emu/bus/coco/cococart.h | 175 |
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__ */ |