Split CoCo and Dragon FDC code, added save state support, fixed regression introduced on the Dragon FDC from 0.154 and general cleanup.

This commit is contained in:
Nathan Woods 2016-09-16 21:07:32 -04:00
parent 636a2bbbf4
commit a2daca9f9d
4 changed files with 646 additions and 586 deletions

View File

@ -2396,6 +2396,7 @@ if (BUSES["COCO"]~=null) then
MAME_DIR .. "src/devices/bus/coco/coco_multi.h",
MAME_DIR .. "src/devices/bus/coco/coco_dwsock.cpp",
MAME_DIR .. "src/devices/bus/coco/coco_dwsock.h",
MAME_DIR .. "src/devices/bus/coco/dragon_fdc.cpp",
}
end

View File

@ -2,16 +2,16 @@
// copyright-holders:Nathan Woods
/*********************************************************************
coco_fdc.c
coco_fdc.cpp
CoCo/Dragon FDC
CoCo Floppy Disk Controller
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.
cartrige, it is dealt with in the main coco.cpp 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
@ -26,53 +26,30 @@
---------------------------------------------------------------------------
DSKREG - the control register
CoCo ($FF40) Dragon ($FF48)
CoCo ($FF40)
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
Bit
7 halt enable flag
6 drive select #3
5 density (0=single, 1=double) and NMI enable flag
4 write precompensation
3 drive motor activation
2 drive select #2
1 drive select #1
0 drive select #0
Reading from $FF48-$FF4F clears bit 7 of DSKREG ($FF40)
---------------------------------------------------------------------------
2007-02-22, P.Harvey-Smith
Began implementing the Dragon Delta Dos controller, this was actually the first
Dragon disk controller 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 controllers except that it used an inverted
data bus, which is the reason the read/write handlers invert the data. This
controller 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 "cococart.h"
#include "coco_fdc.h"
#include "imagedev/flopdrv.h"
#include "includes/coco.h"
#include "imagedev/flopdrv.h"
#include "machine/msm6242.h"
#include "machine/ds1315.h"
#include "machine/wd_fdc.h"
#include "formats/dmk_dsk.h"
#include "formats/jvc_dsk.h"
#include "formats/vdk_dsk.h"
@ -88,15 +65,53 @@
#define DISTO_TAG "disto"
#define CLOUD9_TAG "cloud9"
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
class coco_fdc_device_base : public coco_family_fdc_device_base
{
public:
// construction/destruction
coco_fdc_device_base(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
protected:
enum class rtc_type
{
DISTO = 0x00,
CLOUD9 = 0x01,
NONE = 0xFF
};
// device-level overrides
virtual DECLARE_READ8_MEMBER(read) override;
virtual DECLARE_WRITE8_MEMBER(write) override;
virtual machine_config_constructor device_mconfig_additions() const override;
// methods
virtual void update_lines() override;
void dskreg_w(UINT8 data);
rtc_type real_time_clock();
// devices
required_device<wd1773_t> m_wd17xx;
required_device<ds1315_device> m_ds1315;
required_device_array<floppy_connector, 4> m_floppies;
// Disto RTC
required_device<msm6242_device> m_disto_msm6242; // 6242 RTC on Disto interface
offs_t m_msm6242_rtc_address;
optional_ioport m_rtc;
};
/***************************************************************************
LOCAL VARIABLES
***************************************************************************/
FLOPPY_FORMATS_MEMBER( coco_fdc_device::floppy_formats )
FLOPPY_FORMATS_MEMBER( coco_family_fdc_device_base::floppy_formats )
FLOPPY_DMK_FORMAT,
FLOPPY_JVC_FORMAT,
FLOPPY_VDK_FORMAT
@ -106,166 +121,132 @@ static SLOT_INTERFACE_START( coco_fdc_floppies )
SLOT_INTERFACE("qd", FLOPPY_525_QD)
SLOT_INTERFACE_END
/***************************************************************************
IMPLEMENTATION
***************************************************************************/
/*-------------------------------------------------
real_time_clock
-------------------------------------------------*/
coco_rtc_type_t coco_fdc_device::real_time_clock()
{
coco_rtc_type_t result = coco_rtc_type_t(m_rtc.read_safe(RTC_NONE));
/* check to make sure we don't have any invalid values */
if (((result == RTC_DISTO) && (m_disto_msm6242 == nullptr))
|| ((result == RTC_CLOUD9) && (m_ds1315 == nullptr)))
{
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 MACHINE_CONFIG_FRAGMENT(coco_fdc)
MCFG_WD1773_ADD(WD_TAG, XTAL_8MHz)
MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(coco_fdc_device, fdc_intrq_w))
MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(coco_fdc_device, fdc_drq_w))
MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(coco_fdc_device_base, fdc_intrq_w))
MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(coco_fdc_device_base, fdc_drq_w))
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":0", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":1", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":2", coco_fdc_floppies, "", coco_fdc_device::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":3", coco_fdc_floppies, "", coco_fdc_device::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":0", coco_fdc_floppies, "qd", coco_fdc_device_base::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":1", coco_fdc_floppies, "qd", coco_fdc_device_base::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":2", coco_fdc_floppies, "", coco_fdc_device_base::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":3", coco_fdc_floppies, "", coco_fdc_device_base::floppy_formats)
MCFG_DEVICE_ADD(DISTO_TAG, MSM6242, XTAL_32_768kHz)
MCFG_DS1315_ADD(CLOUD9_TAG)
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 FAMILY FDCs - base class for CoCo/Dragon
//***************************************************************************
//-------------------------------------------------
// coco_fdc_device - constructor
// coco_family_fdc_device_base::device_start
//-------------------------------------------------
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 ), m_owner(nullptr), m_dskreg(0), m_drq(0), m_intrq(0),
m_wd17xx(*this, WD_TAG),
m_wd2797(*this, WD2797_TAG),
m_ds1315(*this, CLOUD9_TAG),
m_disto_msm6242(*this, DISTO_TAG), m_msm6242_rtc_address(0),
m_rtc(*this, ":real_time_clock")
void coco_family_fdc_device_base::device_start()
{
save_item(NAME(m_dskreg));
save_item(NAME(m_intrq));
save_item(NAME(m_drq));
}
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 ), m_owner(nullptr), m_dskreg(0), m_drq(0), m_intrq(0),
m_wd17xx(*this, WD_TAG),
m_wd2797(*this, WD2797_TAG),
m_ds1315(*this, CLOUD9_TAG),
m_disto_msm6242(*this, DISTO_TAG), m_msm6242_rtc_address(0),
m_rtc(*this, ":real_time_clock")
//-------------------------------------------------
// coco_family_fdc_device_base::device_reset
//-------------------------------------------------
void coco_family_fdc_device_base::device_reset()
{
m_dskreg = 0x00;
m_intrq = false;
m_drq = true;
}
//-------------------------------------------------
// coco_family_fdc_device_base::get_cart_base
//-------------------------------------------------
UINT8* coco_family_fdc_device_base::get_cart_base()
{
return memregion("eprom")->base();
}
//***************************************************************************
// COCO FDCs
//***************************************************************************
//-------------------------------------------------
// coco_fdc_device_base - constructor
//-------------------------------------------------
coco_fdc_device_base::coco_fdc_device_base(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_family_fdc_device_base(mconfig, type, name, tag, owner, clock, shortname, source)
, m_wd17xx(*this, WD_TAG)
, m_ds1315(*this, CLOUD9_TAG)
, m_floppies(*this, WD_TAG ":%u", 0)
, m_disto_msm6242(*this, DISTO_TAG)
, m_msm6242_rtc_address(0)
, m_rtc(*this, ":real_time_clock")
{
}
//-------------------------------------------------
// device_start - device-specific startup
// real_time_clock
//-------------------------------------------------
void coco_fdc_device::device_start()
coco_fdc_device_base::rtc_type coco_fdc_device_base::real_time_clock()
{
m_owner = dynamic_cast<cococart_slot_device *>(owner());
m_drq = 1;
m_dskreg = 0x00;
m_intrq = 0;
m_msm6242_rtc_address = 0;
rtc_type result = (rtc_type) m_rtc.read_safe((ioport_value) rtc_type::NONE);
// check to make sure we don't have any invalid values
if (((result == rtc_type::DISTO) && (m_disto_msm6242 == nullptr))
|| ((result == rtc_type::CLOUD9) && (m_ds1315 == nullptr)))
{
result = rtc_type::NONE;
}
return result;
}
//-------------------------------------------------
// machine_config_additions - device-specific
// machine configurations
//-------------------------------------------------
machine_config_constructor coco_fdc_device::device_mconfig_additions() const
machine_config_constructor coco_fdc_device_base::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( coco_fdc );
return MACHINE_CONFIG_NAME(coco_fdc);
}
//-------------------------------------------------
// rom_region - device-specific ROM region
// update_lines - CoCo specific disk
// controller lines
//-------------------------------------------------
const tiny_rom_entry *coco_fdc_device::device_rom_region() const
void coco_fdc_device_base::update_lines()
{
return ROM_NAME( coco_fdc );
// clear HALT enable under certain circumstances
if (intrq() && (dskreg() & 0x20))
set_dskreg(dskreg() & ~0x80); // clear halt enable
// set the NMI line
cart_set_line(cococart_slot_device::line::NMI, intrq() && (dskreg() & 0x20));
// set the HALT line
cart_set_line(cococart_slot_device::line::HALT, !drq() && (dskreg() & 0x80));
}
/*-------------------------------------------------
get_cart_base
-------------------------------------------------*/
UINT8* coco_fdc_device::get_cart_base()
{
return memregion("eprom")->base();
}
//-------------------------------------------------
// dskreg_w - function to write to CoCo dskreg
//-------------------------------------------------
/*-------------------------------------------------
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_slot_device::line::NMI,
((m_intrq != 0) && (m_dskreg & 0x20)) ? cococart_slot_device::line_value::ASSERT : cococart_slot_device::line_value::CLEAR);
/* set the HALT line */
m_owner->cart_set_line(cococart_slot_device::line::HALT,
((m_drq == 0) && (m_dskreg & 0x80)) ? cococart_slot_device::line_value::ASSERT : cococart_slot_device::line_value::CLEAR);
}
/*-------------------------------------------------
dskreg_w - function to write to CoCo
dskreg
-------------------------------------------------*/
void coco_fdc_device::dskreg_w(UINT8 data)
void coco_fdc_device_base::dskreg_w(UINT8 data)
{
UINT8 drive = 0;
UINT8 head;
@ -300,38 +281,34 @@ void coco_fdc_device::dskreg_w(UINT8 data)
else if (data & 0x40)
drive = 3;
floppy_image_device *floppy[4];
floppy[0] = subdevice<floppy_connector>(WD_TAG ":0")->get_device();
floppy[1] = subdevice<floppy_connector>(WD_TAG ":1")->get_device();
floppy[2] = subdevice<floppy_connector>(WD_TAG ":2")->get_device();
floppy[3] = subdevice<floppy_connector>(WD_TAG ":3")->get_device();
for (int i = 0; i < 4; i++)
{
if (floppy[i])
floppy[i]->mon_w(i == drive ? CLEAR_LINE : ASSERT_LINE);
floppy_image_device *floppy = m_floppies[i]->get_device();
if (floppy)
floppy->mon_w(i == drive ? CLEAR_LINE : ASSERT_LINE);
}
head = ((data & 0x40) && (drive != 3)) ? 1 : 0;
m_dskreg = data;
set_dskreg(data);
update_lines();
m_wd17xx->set_floppy(floppy[drive]);
floppy_image_device *selected_floppy = m_floppies[drive]->get_device();
m_wd17xx->set_floppy(selected_floppy);
if (floppy[drive])
floppy[drive]->ss_w(head);
if (selected_floppy)
selected_floppy->ss_w(head);
m_wd17xx->dden_w(!BIT(m_dskreg, 5));
m_wd17xx->dden_w(!BIT(dskreg(), 5));
}
/*-------------------------------------------------
read
-------------------------------------------------*/
READ8_MEMBER(coco_fdc_device::read)
//-------------------------------------------------
// read
//-------------------------------------------------
READ8_MEMBER(coco_fdc_device_base::read)
{
UINT8 result = 0;
@ -355,22 +332,22 @@ READ8_MEMBER(coco_fdc_device::read)
switch(offset)
{
case 0x10: /* FF50 */
if (real_time_clock() == RTC_DISTO)
if (real_time_clock() == rtc_type::DISTO)
result = m_disto_msm6242->read(space,m_msm6242_rtc_address);
break;
case 0x38: /* FF78 */
if (real_time_clock() == RTC_CLOUD9)
if (real_time_clock() == rtc_type::CLOUD9)
m_ds1315->read_0(space, offset);
break;
case 0x39: /* FF79 */
if (real_time_clock() == RTC_CLOUD9)
if (real_time_clock() == rtc_type::CLOUD9)
m_ds1315->read_1(space, offset);
break;
case 0x3C: /* FF7C */
if (real_time_clock() == RTC_CLOUD9)
if (real_time_clock() == rtc_type::CLOUD9)
result = m_ds1315->read_data(space, offset);
break;
}
@ -379,11 +356,11 @@ READ8_MEMBER(coco_fdc_device::read)
/*-------------------------------------------------
write
-------------------------------------------------*/
//-------------------------------------------------
// write
//-------------------------------------------------
WRITE8_MEMBER(coco_fdc_device::write)
WRITE8_MEMBER(coco_fdc_device_base::write)
{
switch(offset & 0x1F)
{
@ -410,12 +387,12 @@ WRITE8_MEMBER(coco_fdc_device::write)
switch(offset)
{
case 0x10: /* FF50 */
if (real_time_clock() == RTC_DISTO)
if (real_time_clock() == rtc_type::DISTO)
m_disto_msm6242->write(space,m_msm6242_rtc_address, data);
break;
case 0x11: /* FF51 */
if (real_time_clock() == RTC_DISTO)
if (real_time_clock() == rtc_type::DISTO)
m_msm6242_rtc_address = data & 0x0f;
break;
}
@ -423,293 +400,134 @@ WRITE8_MEMBER(coco_fdc_device::write)
//**************************************************************************
// DRAGON FDC
// COCO FDC
//**************************************************************************
static MACHINE_CONFIG_FRAGMENT(dragon_fdc)
MCFG_WD2797_ADD(WD2797_TAG, XTAL_1MHz)
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":0", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":1", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":2", coco_fdc_floppies, "", coco_fdc_device::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":3", coco_fdc_floppies, "", coco_fdc_device::floppy_formats)
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_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 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)
namespace
{
}
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_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 tiny_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_slot_device::line::NMI,
((m_intrq != 0) && (m_dskreg & 0x20)) ? cococart_slot_device::line_value::ASSERT : cococart_slot_device::line_value::CLEAR);
/* set the CART line */
m_owner->cart_set_line(cococart_slot_device::line::CART,
(m_drq != 0) ? cococart_slot_device::line_value::ASSERT : cococart_slot_device::line_value::CLEAR);
}
/*-------------------------------------------------
dskreg_w - function to write to
Dragon dskreg
-------------------------------------------------*/
void dragon_fdc_device::dskreg_w(UINT8 data)
{
if (LOG_FDC)
class coco_fdc_device : public coco_fdc_device_base
{
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);
}
public:
// construction/destruction
coco_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: coco_fdc_device_base(mconfig, COCO_FDC, "CoCo FDC", tag, owner, clock, "coco_fdc", __FILE__)
{
}
floppy_image_device *floppy = nullptr;
protected:
// optional information overrides
virtual const tiny_rom_entry *device_rom_region() const override
{
return ROM_NAME(coco_fdc);
}
switch (data & 0x03)
{
case 0: floppy = subdevice<floppy_connector>(WD2797_TAG ":0")->get_device(); break;
case 1: floppy = subdevice<floppy_connector>(WD2797_TAG ":1")->get_device(); break;
case 2: floppy = subdevice<floppy_connector>(WD2797_TAG ":2")->get_device(); break;
case 3: floppy = subdevice<floppy_connector>(WD2797_TAG ":3")->get_device(); break;
}
m_wd2797->set_floppy(floppy);
m_wd2797->dden_w(BIT(data, 3));
m_dskreg = data;
}
/*-------------------------------------------------
read
-------------------------------------------------*/
READ8_MEMBER(dragon_fdc_device::read)
{
UINT8 result = 0;
switch(offset & 0xEF)
{
case 0:
result = m_wd2797->status_r(space, 0);
break;
case 1:
result = m_wd2797->track_r(space, 0);
break;
case 2:
result = m_wd2797->sector_r(space, 0);
break;
case 3:
result = m_wd2797->data_r(space, 0);
break;
}
return result;
}
/*-------------------------------------------------
write
-------------------------------------------------*/
WRITE8_MEMBER(dragon_fdc_device::write)
{
switch(offset & 0xEF)
{
case 0:
m_wd2797->cmd_w(space, 0, data);
break;
case 1:
m_wd2797->track_w(space, 0, data);
break;
case 2:
m_wd2797->sector_w(space, 0, data);
break;
case 3:
m_wd2797->data_w(space, 0, data);
break;
case 8: case 9: case 10: case 11:
case 12: case 13: case 14: case 15:
dskreg_w(data);
break;
};
}
const device_type COCO_FDC = &device_creator<coco_fdc_device>;
//**************************************************************************
// 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 tiny_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_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
namespace
{
class coco_fdc_v11_device : public coco_fdc_device_base
{
public:
// construction/destruction
coco_fdc_v11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: coco_fdc_device_base(mconfig, COCO_FDC_V11, "CoCo FDC v1.1", tag, owner, clock, "coco_fdc_v11", __FILE__)
{
}
protected:
// optional information overrides
virtual const tiny_rom_entry *device_rom_region() const override
{
return ROM_NAME(coco_fdc_v11);
}
};
};
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 tiny_rom_entry *coco_fdc_v11_device::device_rom_region() const
{
return ROM_NAME( coco_fdc_v11 );
}
//**************************************************************************
// COCO-3 HDB-DOS
//**************************************************************************
ROM_START( coco3_hdb1 )
ROM_REGION(0x8000,"eprom",ROMREGION_ERASE00)
ROM_LOAD("hdbdw3bc3.rom", 0x0000, 0x2000, CRC(309a9efd) SHA1(671605d61811953860466f771c1594bbade331f4))
ROM_START(coco3_hdb1)
ROM_REGION(0x8000, "eprom", ROMREGION_ERASE00)
ROM_LOAD("hdbdw3bc3.rom", 0x0000, 0x2000, CRC(309a9efd) SHA1(671605d61811953860466f771c1594bbade331f4))
ROM_RELOAD(0x2000, 0x2000)
ROM_RELOAD(0x4000, 0x2000)
ROM_RELOAD(0x6000, 0x2000)
ROM_END
namespace
{
class coco3_hdb1_device : public coco_fdc_device_base
{
public:
// construction/destruction
coco3_hdb1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: coco_fdc_device_base(mconfig, COCO3_HDB1, "CoCo3 HDB-DOS", tag, owner, clock, "coco3_hdb1", __FILE__)
{
}
protected:
// optional information overrides
virtual const tiny_rom_entry *device_rom_region() const override
{
return ROM_NAME(coco3_hdb1);
}
};
};
const device_type COCO3_HDB1 = &device_creator<coco3_hdb1_device>;
coco3_hdb1_device::coco3_hdb1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: coco_fdc_device(mconfig, COCO3_HDB1, "CoCo3 HDB-DOS", tag, owner, clock, "coco3_hdb1", __FILE__)
{
}
const tiny_rom_entry *coco3_hdb1_device::device_rom_region() const
{
return ROM_NAME( coco3_hdb1 );
}
//**************************************************************************
// CP400 FDC
//**************************************************************************
ROM_START( cp400_fdc )
ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00)
ROM_LOAD("cp400dsk.rom", 0x0000, 0x2000, CRC(e9ad60a0) SHA1(827697fa5b755f5dc1efb054cdbbeb04e405405b))
ROM_START(cp400_fdc)
ROM_REGION(0x4000, "eprom", ROMREGION_ERASE00)
ROM_LOAD("cp400dsk.rom", 0x0000, 0x2000, CRC(e9ad60a0) SHA1(827697fa5b755f5dc1efb054cdbbeb04e405405b))
ROM_END
namespace
{
class cp400_fdc_device : public coco_fdc_device_base
{
public:
// construction/destruction
cp400_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: coco_fdc_device_base(mconfig, CP400_FDC, "CP400 FDC", tag, owner, clock, "cp400_fdc", __FILE__)
{
}
protected:
// optional information overrides
virtual const tiny_rom_entry *device_rom_region() const override
{
return ROM_NAME(cp400_fdc);
}
};
};
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 tiny_rom_entry *cp400_fdc_device::device_rom_region() const
{
return ROM_NAME( cp400_fdc );
}

View File

@ -1,180 +1,88 @@
// license:BSD-3-Clause
// copyright-holders:Nathan Woods
#pragma once
/*********************************************************************
#ifndef __COCO_FDC_H__
#define __COCO_FDC_H__
coco_fdc.h
CoCo/Dragon Floppy Disk Controller
*********************************************************************/
#ifndef MAME_DEVICES_BUS_COCO_FDC_H
#define MAME_DEVICES_BUS_COCO_FDC_H
#include "emu.h"
#include "cococart.h"
#include "machine/msm6242.h"
#include "machine/ds1315.h"
#include "machine/wd_fdc.h"
#include "imagedev/floppy.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
// ======================> coco_rtc_type_t
// ======================> coco_family_fdc_device_base
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
class coco_family_fdc_device_base :
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);
// construction/destruction
coco_family_fdc_device_base(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)
{
m_owner = dynamic_cast<cococart_slot_device *>(owner);
};
DECLARE_FLOPPY_FORMATS(floppy_formats);
DECLARE_WRITE_LINE_MEMBER(fdc_intrq_w) { m_intrq = state; update_lines(); }
DECLARE_WRITE_LINE_MEMBER(fdc_drq_w) { m_drq = state; update_lines(); }
// optional information overrides
virtual machine_config_constructor device_mconfig_additions() const override;
virtual const tiny_rom_entry *device_rom_region() const override;
DECLARE_FLOPPY_FORMATS(floppy_formats);
virtual UINT8* get_cart_base() override;
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() override;
virtual DECLARE_READ8_MEMBER(read) override;
virtual DECLARE_WRITE8_MEMBER(write) override;
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
coco_rtc_type_t real_time_clock();
// FDC overrides
virtual void update_lines() = 0;
virtual UINT8* get_cart_base() override;
// internal state
cococart_slot_device *m_owner;
// wrapper for setting the cart line
void cart_set_line(cococart_slot_device::line which, cococart_slot_device::line_value value)
{
m_owner->cart_set_line(which, value);
}
void cart_set_line(cococart_slot_device::line which, bool value)
{
cart_set_line(which, value ? cococart_slot_device::line_value::ASSERT : cococart_slot_device::line_value::CLEAR);
}
UINT8 m_dskreg;
UINT8 m_drq : 1;
UINT8 m_intrq : 1;
// accessors
UINT8 dskreg() const { return m_dskreg; }
bool intrq() const { return m_intrq; }
bool drq() const { return m_drq; }
void set_dskreg(UINT8 data) { m_dskreg = data; }
optional_device<wd1773_t> m_wd17xx; /* WD17xx */
optional_device<wd2797_t> m_wd2797; /* WD2797 */
optional_device<ds1315_device> m_ds1315; /* DS1315 */
private:
// internal state
cococart_slot_device *m_owner;
/* Disto RTC */
optional_device<msm6242_device> m_disto_msm6242; /* 6242 RTC on Disto interface */
offs_t m_msm6242_rtc_address;
optional_ioport m_rtc;
// registers
UINT8 m_dskreg;
bool m_intrq;
bool m_drq;
};
// device type definition
// device type definitions - CoCo FDC
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 tiny_rom_entry *device_rom_region() const override;
};
// device type definition
extern const device_type COCO_FDC_V11;
// ======================> coco3_hdb1_device
class coco3_hdb1_device :
public coco_fdc_device
{
public:
// construction/destruction
coco3_hdb1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
// optional information overrides
virtual const tiny_rom_entry *device_rom_region() const override;
};
// device type definition
extern const device_type COCO3_HDB1;
// ======================> 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 tiny_rom_entry *device_rom_region() const override;
};
// 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 override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void update_lines() override;
virtual void dskreg_w(UINT8 data) override;
protected:
// device-level overrides
virtual void device_start() override;
virtual DECLARE_READ8_MEMBER(read) override;
virtual DECLARE_WRITE8_MEMBER(write) override;
};
// device type definition
// device type definitions - Dragon FDC
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 tiny_rom_entry *device_rom_region() const override;
};
// device type definition
extern const device_type SDTANDY_FDC;
#endif /* __COCO_FDC_H__ */
#endif // MAME_DEVICES_BUS_COCO_FDC_H

View File

@ -0,0 +1,333 @@
// license:BSD-3-Clause
// copyright-holders:Nathan Woods
/*********************************************************************
dragon_fdc.cpp
Dragon Floppy Disk Controller
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.cpp 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
Dragon ($FF48)
Bit
7 not used
6 not used
5 NMI enable flag
4 write precompensation
3 single density enable
2 drive motor activation
1 drive select high bit
0 drive select low bit
---------------------------------------------------------------------------
2007-02-22, P.Harvey-Smith
Began implementing the Dragon Delta Dos controller, this was actually the first
Dragon disk controller 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 controllers except that it used an inverted
data bus, which is the reason the read/write handlers invert the data. This
controller 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 "cococart.h"
#include "coco_fdc.h"
#include "imagedev/flopdrv.h"
#include "includes/coco.h"
#include "machine/wd_fdc.h"
#include "formats/dmk_dsk.h"
#include "formats/jvc_dsk.h"
#include "formats/vdk_dsk.h"
/***************************************************************************
PARAMETERS
***************************************************************************/
#define LOG_FDC 0
#define WD2797_TAG "wd2797"
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
namespace
{
class dragon_fdc_device_base : public coco_family_fdc_device_base
{
public:
// construction/destruction
dragon_fdc_device_base(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
protected:
// device-level overrides
virtual DECLARE_READ8_MEMBER(read) override;
virtual DECLARE_WRITE8_MEMBER(write) override;
virtual machine_config_constructor device_mconfig_additions() const override;
virtual void update_lines() override;
private:
// device references
required_device<wd2797_t> m_wd2797;
required_device_array<floppy_connector, 4> m_floppies;
// methods
void dskreg_w(UINT8 data);
};
};
/***************************************************************************
LOCAL VARIABLES
***************************************************************************/
static SLOT_INTERFACE_START(dragon_fdc_device_base)
SLOT_INTERFACE("qd", FLOPPY_525_QD)
SLOT_INTERFACE_END
static MACHINE_CONFIG_FRAGMENT(dragon_fdc)
MCFG_WD2797_ADD(WD2797_TAG, XTAL_1MHz)
MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(dragon_fdc_device_base, fdc_intrq_w))
MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(dragon_fdc_device_base, fdc_drq_w))
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":0", dragon_fdc_device_base, "qd", dragon_fdc_device_base::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":1", dragon_fdc_device_base, "qd", dragon_fdc_device_base::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":2", dragon_fdc_device_base, "", dragon_fdc_device_base::floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":3", dragon_fdc_device_base, "", dragon_fdc_device_base::floppy_formats)
MACHINE_CONFIG_END
//**************************************************************************
// IMPLEMENTATION
//**************************************************************************
//-------------------------------------------------
// dragon_fdc_device_base - constructor
//-------------------------------------------------
dragon_fdc_device_base::dragon_fdc_device_base(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_family_fdc_device_base(mconfig, type, name, tag, owner, clock, shortname, source)
, m_wd2797(*this, WD2797_TAG)
, m_floppies(*this, WD2797_TAG ":%u", 0)
{
}
//-------------------------------------------------
// machine_config_additions - device-specific
// machine configurations
//-------------------------------------------------
machine_config_constructor dragon_fdc_device_base::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME(dragon_fdc);
}
//-------------------------------------------------
// update_lines - Dragon specific disk
// controller lines
//-------------------------------------------------
void dragon_fdc_device_base::update_lines()
{
// set the NMI line
cart_set_line(cococart_slot_device::line::NMI, intrq() && (dskreg() & 0x20));
// set the CART line
cart_set_line(cococart_slot_device::line::CART, drq());
}
//-------------------------------------------------
// dskreg_w - function to write to
// Dragon dskreg
//-------------------------------------------------
void dragon_fdc_device_base::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);
}
// update the motor on each floppy
for (int i = 0; i < 4; i++)
{
floppy_image_device *floppy = m_floppies[i]->get_device();
if (floppy)
floppy->mon_w((data && 0x04) && (i == (data & 0x03)) ? CLEAR_LINE : ASSERT_LINE);
}
// manipulate the WD2797
m_wd2797->set_floppy(m_floppies[data & 0x03]->get_device());
m_wd2797->dden_w(BIT(data, 3));
set_dskreg(data);
}
//-------------------------------------------------
// read
//-------------------------------------------------
READ8_MEMBER(dragon_fdc_device_base::read)
{
UINT8 result = 0;
switch (offset & 0xEF)
{
case 0:
result = m_wd2797->status_r(space, 0);
break;
case 1:
result = m_wd2797->track_r(space, 0);
break;
case 2:
result = m_wd2797->sector_r(space, 0);
break;
case 3:
result = m_wd2797->data_r(space, 0);
break;
}
return result;
}
//-------------------------------------------------
// write
//-------------------------------------------------
WRITE8_MEMBER(dragon_fdc_device_base::write)
{
switch (offset & 0xEF)
{
case 0:
m_wd2797->cmd_w(space, 0, data);
break;
case 1:
m_wd2797->track_w(space, 0, data);
break;
case 2:
m_wd2797->sector_w(space, 0, data);
break;
case 3:
m_wd2797->data_w(space, 0, data);
break;
case 8: case 9: case 10: case 11:
case 12: case 13: case 14: case 15:
dskreg_w(data);
break;
};
}
//**************************************************************************
// DRAGON FDC
//**************************************************************************
ROM_START(dragon_fdc)
ROM_REGION(0x4000, "eprom", ROMREGION_ERASE00)
ROM_LOAD_OPTIONAL("ddos10.rom", 0x0000, 0x2000, CRC(b44536f6) SHA1(a8918c71d319237c1e3155bb38620acb114a80bc))
ROM_END
namespace
{
class dragon_fdc_device : public dragon_fdc_device_base
{
public:
// construction/destruction
dragon_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: dragon_fdc_device_base(mconfig, DRAGON_FDC, "Dragon FDC", tag, owner, clock, "dragon_fdc", __FILE__)
{
}
protected:
// optional information overrides
virtual const tiny_rom_entry *device_rom_region() const override
{
return ROM_NAME(dragon_fdc);
}
};
};
const device_type DRAGON_FDC = &device_creator<dragon_fdc_device>;
//**************************************************************************
// 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
namespace
{
class sdtandy_fdc_device : public dragon_fdc_device_base
{
public:
// construction/destruction
sdtandy_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: dragon_fdc_device_base(mconfig, SDTANDY_FDC, "SDTANDY FDC", tag, owner, clock, "sdtandy_fdc", __FILE__)
{
}
protected:
// optional information overrides
virtual const tiny_rom_entry *device_rom_region() const override
{
return ROM_NAME(sdtandy_fdc);
}
};
};
const device_type SDTANDY_FDC = &device_creator<sdtandy_fdc_device>;