diff options
| author | 2025-10-26 13:56:39 -0400 | |
|---|---|---|
| committer | 2025-10-26 14:06:05 -0400 | |
| commit | f69ba6ec9fbb2cfbd3693e1ad084d2f9acf98d17 (patch) | |
| tree | 5133ee227bd4f80210d995d406c9aaf9a13279b9 | |
| parent | 6e0e442a2d06596c1585e2c68392ec3fec0df392 (diff) | |
Coleco Adam floppy disk emulation improvements
- Completely reimplement Adam .dsk floppy format, permuting sectors of 720KB and 1.44MB 3.5" formats into (and out of) the correct native interleave
- Split adam_fdc device into several sets, some now properly supporting 720KB and/or 1.44MB formats
- Remove the "Doug Slopsema" BIOS for the 320KB FDC variant upon determining it to be a copy of the 320ta BIOS with slight bitrot
| -rw-r--r-- | src/devices/bus/adamnet/adamnet.cpp | 4 | ||||
| -rw-r--r-- | src/devices/bus/adamnet/fdc.cpp | 240 | ||||
| -rw-r--r-- | src/devices/bus/adamnet/fdc.h | 86 | ||||
| -rw-r--r-- | src/lib/formats/adam_dsk.cpp | 377 | ||||
| -rw-r--r-- | src/lib/formats/adam_dsk.h | 20 | ||||
| -rw-r--r-- | src/mame/coleco/adam.cpp | 7 |
6 files changed, 639 insertions, 95 deletions
diff --git a/src/devices/bus/adamnet/adamnet.cpp b/src/devices/bus/adamnet/adamnet.cpp index c2886c61248..220c13662c0 100644 --- a/src/devices/bus/adamnet/adamnet.cpp +++ b/src/devices/bus/adamnet/adamnet.cpp @@ -261,6 +261,10 @@ void adamnet_devices(device_slot_interface &device) { device.option_add("ddp", ADAM_DDP); device.option_add("fdc", ADAM_FDC); + device.option_add("fdc_320kb", ADAM_FDC_320KB); + device.option_add("fdc_a720dipi", ADAM_FDC_A720DIPI); + device.option_add("fdc_fp720at", ADAM_FDC_FP720AT); + device.option_add("fdc_mihddd", ADAM_FDC_MIHDDD); device.option_add("kb", ADAM_KB); device.option_add("prn", ADAM_PRN); device.option_add("spi", ADAM_SPI); diff --git a/src/devices/bus/adamnet/fdc.cpp b/src/devices/bus/adamnet/fdc.cpp index b53e655b485..d79aecf849e 100644 --- a/src/devices/bus/adamnet/fdc.cpp +++ b/src/devices/bus/adamnet/fdc.cpp @@ -8,17 +8,21 @@ /* - TODO: + Note: the 3.5" controllers are not compatible with 5.25" drives, + and vice versa, due to differences in disk geometry and sector + interleaving. - - 320KB DSDD 5.25" - - 720KB DSDD 3.5" - - 1.44MB DSHD 3.5" + 640KB DSQD 5.25" disks are rumored to have also been used on the + Adam, but no images of these are confirmed to exist and they are + not supported by any extant FDC variant. */ #include "emu.h" #include "fdc.h" +#include "machine/clock.h" + #include "formats/adam_dsk.h" @@ -37,6 +41,10 @@ //************************************************************************** DEFINE_DEVICE_TYPE(ADAM_FDC, adam_fdc_device, "adam_fdc", "Adam FDC") +DEFINE_DEVICE_TYPE(ADAM_FDC_320KB, adam_fdc_320kb_device, "adam_fdc_320kb", "Adam FDC (320KB DSDD modification)") +DEFINE_DEVICE_TYPE(ADAM_FDC_A720DIPI, adam_fdc_a720dipi_device, "adam_fdc_a720dipi", "Adam FDC (720KB 3.5\" A720DIPI)") +DEFINE_DEVICE_TYPE(ADAM_FDC_FP720AT, adam_fdc_fp720at_device, "adam_fdc_fp720at", "Adam FDC (720KB 3.5\" FastPack 720A(T))") +DEFINE_DEVICE_TYPE(ADAM_FDC_MIHDDD, adam_fdc_mihddd_device, "adam_fdc_mihddd", "Adam FDC (1.44MB 3.5\" Micro Innovations HD-DD)") //------------------------------------------------- @@ -45,23 +53,56 @@ DEFINE_DEVICE_TYPE(ADAM_FDC, adam_fdc_device, "adam_fdc", "Adam FDC") ROM_START( adam_fdc ) ROM_REGION( 0x1000, M6801_TAG, 0 ) - ROM_DEFAULT_BIOS("ssdd") - ROM_SYSTEM_BIOS( 0, "ssdd", "Coleco 160KB SSDD" ) - ROMX_LOAD( "adam disk u10 ad 31 rev a 09-27-84.u10", 0x0000, 0x1000, CRC(4b0b7143) SHA1(1cb68891c3af80e99efad7e309136ca37244f060), ROM_BIOS(0) ) - ROM_SYSTEM_BIOS( 1, "320ta", "320KB DSDD (Minh Ta?)" ) - ROMX_LOAD( "320ta.u10", 0x0000, 0x1000, CRC(dcd865b3) SHA1(dde583e0d18ce4406e9ea44ab34d083e73ee30e2), ROM_BIOS(1) ) - ROM_SYSTEM_BIOS( 2, "dbl24", "320KB DSDD (DBL)" ) - ROMX_LOAD( "dbl2-4.u10", 0x0000, 0x1000, CRC(5df49f15) SHA1(43d5710e4fb05f520e813869a049585b41ada86b), ROM_BIOS(2) ) - ROM_SYSTEM_BIOS( 3, "320doug", "320KB DSDD (Doug Slopsema)" ) - ROMX_LOAD( "doug.u10", 0x0000, 0x1000, CRC(2b2a9c6d) SHA1(e40304cbb6b9f174d9f5762d920983c79c899b3e), ROM_BIOS(3) ) - ROM_SYSTEM_BIOS( 4, "a720dipi", "720KB 3.5\" A720DIPI 7607 MMSG" ) - ROMX_LOAD( "a720dipi 7607 mmsg =c= 1988.u10", 0x0000, 0x1000, CRC(5f248557) SHA1(15b3aaebba38af84f6a1a6ccdf840ca3d58635da), ROM_BIOS(4) ) - ROM_SYSTEM_BIOS( 5, "fp720at", "720KB 3.5\" FastPack 720A(T)" ) - ROMX_LOAD( "fastpack 720a,t.u10", 0x0000, 0x1000, CRC(8f952c88) SHA1(e593a89d7c6e7ea99e7ce376ffa2732d7b646d49), ROM_BIOS(5) ) - ROM_SYSTEM_BIOS( 6, "mihddd", "1.44MB 3.5\" Micro Innovations HD-DD" ) - ROMX_LOAD( "1440k micro innovations hd-dd.u10", 0x0000, 0x1000, CRC(2efec8c0) SHA1(f6df22339c93dca938b65d0cbe23abcad89ec230), ROM_BIOS(6) ) - ROM_SYSTEM_BIOS( 7, "pmhd", "1.44MB 3.5\" Powermate High Density" ) - ROMX_LOAD( "pmhdfdc.u10", 0x0000, 0x1000, CRC(fed4006c) SHA1(bc8dd00dd5cde9500a4cd7dc1e4d74330184472a), ROM_BIOS(7) ) + //ROM_SYSTEM_BIOS( n, "ssdd", "Coleco 160KB SSDD" ) + ROM_LOAD( "adam disk u10 ad 31 rev a 09-27-84.u10", 0x0000, 0x1000, CRC(4b0b7143) SHA1(1cb68891c3af80e99efad7e309136ca37244f060) ) +ROM_END + + +//------------------------------------------------- +// ROM( adam_fdc_320kb ) +//------------------------------------------------- + +ROM_START( adam_fdc_320kb ) + ROM_REGION( 0x1000, M6801_TAG, 0 ) + ROM_DEFAULT_BIOS( "320ta" ) + ROM_SYSTEM_BIOS( 0, "320ta", "Minh Ta?" ) + ROMX_LOAD( "320ta.u10", 0x0000, 0x1000, CRC(dcd865b3) SHA1(dde583e0d18ce4406e9ea44ab34d083e73ee30e2), ROM_BIOS(0) ) + ROM_SYSTEM_BIOS( 1, "dbl24", "DBL" ) + ROMX_LOAD( "dbl2-4.u10", 0x0000, 0x1000, CRC(5df49f15) SHA1(43d5710e4fb05f520e813869a049585b41ada86b), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 2, "pmhd", "PMHD" ) // formerly listed as 1.44MB 3.5" Powermate High Density but actually a bugfixed version of "dbl24" + ROMX_LOAD( "pmhdfdc.u10", 0x0000, 0x1000, CRC(fed4006c) SHA1(bc8dd00dd5cde9500a4cd7dc1e4d74330184472a), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// ROM( adam_fdc_a720dipi ) +//------------------------------------------------- + +ROM_START( adam_fdc_a720dipi ) + ROM_REGION( 0x1000, M6801_TAG, 0 ) + //ROM_SYSTEM_BIOS( n, "a720dipi", "720KB 3.5\" A720DIPI 7607 MMSG" ) + ROM_LOAD( "a720dipi 7607 mmsg =c= 1988.u10", 0x0000, 0x1000, CRC(5f248557) SHA1(15b3aaebba38af84f6a1a6ccdf840ca3d58635da) ) +ROM_END + + +//------------------------------------------------- +// ROM( adam_fdc_fp720at ) +//------------------------------------------------- + +ROM_START( adam_fdc_fp720at ) + ROM_REGION( 0x1000, M6801_TAG, 0 ) + //ROM_SYSTEM_BIOS( n, "fp720at", "720KB 3.5\" FastPack 720A(T)" ) + ROM_LOAD( "fastpack 720a,t.u10", 0x0000, 0x1000, CRC(8f952c88) SHA1(e593a89d7c6e7ea99e7ce376ffa2732d7b646d49) ) +ROM_END + + +//------------------------------------------------- +// ROM( adam_fdc_mihddd ) +//------------------------------------------------- + +ROM_START( adam_fdc_mihddd ) + ROM_REGION( 0x1000, M6801_TAG, 0 ) + ROM_LOAD( "1440k micro innovations hd-dd.u10", 0x0000, 0x1000, CRC(2efec8c0) SHA1(f6df22339c93dca938b65d0cbe23abcad89ec230) ) ROM_END @@ -74,6 +115,26 @@ const tiny_rom_entry *adam_fdc_device::device_rom_region() const return ROM_NAME( adam_fdc ); } +const tiny_rom_entry *adam_fdc_320kb_device::device_rom_region() const +{ + return ROM_NAME( adam_fdc_320kb ); +} + +const tiny_rom_entry *adam_fdc_a720dipi_device::device_rom_region() const +{ + return ROM_NAME( adam_fdc_a720dipi ); +} + +const tiny_rom_entry *adam_fdc_fp720at_device::device_rom_region() const +{ + return ROM_NAME( adam_fdc_fp720at ); +} + +const tiny_rom_entry *adam_fdc_mihddd_device::device_rom_region() const +{ + return ROM_NAME( adam_fdc_mihddd ); +} + //------------------------------------------------- // ADDRESS_MAP( fdc6801_mem ) @@ -107,12 +168,28 @@ void adam_fdc_device::floppy_formats(format_registration &fr) fr.add(FLOPPY_ADAM_FORMAT); } -static void adam_fdc_floppies(device_slot_interface &device) +static void adam_160kb_floppies(device_slot_interface &device) +{ + device.option_add("525ssdd", FLOPPY_525_SSDD); +} + +static void adam_320kb_floppies(device_slot_interface &device) { device.option_add("525ssdd", FLOPPY_525_SSDD); device.option_add("525dsdd", FLOPPY_525_DD); } +static void adam_720kb_floppies(device_slot_interface &device) +{ + device.option_add("35dd", FLOPPY_35_DD); +} + +static void adam_1440kb_floppies(device_slot_interface &device) +{ + device.option_add("35dd", FLOPPY_35_DD); + device.option_add("35hd", FLOPPY_35_HD); +} + //------------------------------------------------- // device_add_mconfig - add device configuration @@ -120,7 +197,7 @@ static void adam_fdc_floppies(device_slot_interface &device) void adam_fdc_device::device_add_mconfig(machine_config &config) { - M6803(config, m_maincpu, 4_MHz_XTAL), + M6803(config, m_maincpu, 4_MHz_XTAL); m_maincpu->set_addrmap(AS_PROGRAM, &adam_fdc_device::adam_fdc_mem); m_maincpu->in_p1_cb().set(FUNC(adam_fdc_device::p1_r)); m_maincpu->out_p1_cb().set(FUNC(adam_fdc_device::p1_w)); @@ -130,7 +207,42 @@ void adam_fdc_device::device_add_mconfig(machine_config &config) WD2793(config, m_fdc, 4_MHz_XTAL / 4); m_fdc->intrq_wr_callback().set_inputline(m_maincpu, INPUT_LINE_NMI); - FLOPPY_CONNECTOR(config, m_connector, adam_fdc_floppies, "525ssdd", adam_fdc_device::floppy_formats).enable_sound(true); + FLOPPY_CONNECTOR(config, m_connector, adam_160kb_floppies, "525ssdd", adam_fdc_device::floppy_formats).enable_sound(true); +} + +void adam_fdc_320kb_device::device_add_mconfig(machine_config &config) +{ + adam_fdc_device::device_add_mconfig(config); + + FLOPPY_CONNECTOR(config.replace(), m_connector, adam_320kb_floppies, "525dsdd", adam_fdc_320kb_device::floppy_formats).enable_sound(true); +} + +void adam_fdc_a720dipi_device::device_add_mconfig(machine_config &config) +{ + adam_fdc_device::device_add_mconfig(config); + + FLOPPY_CONNECTOR(config.replace(), m_connector, adam_720kb_floppies, "35dd", adam_fdc_a720dipi_device::floppy_formats).enable_sound(true); +} + +void adam_fdc_fp720at_device::device_add_mconfig(machine_config &config) +{ + adam_fdc_device::device_add_mconfig(config); + + FLOPPY_CONNECTOR(config.replace(), m_connector, adam_720kb_floppies, "35dd", adam_fdc_fp720at_device::floppy_formats).enable_sound(true); +} + +void adam_fdc_mihddd_device::device_add_mconfig(machine_config &config) +{ + adam_fdc_device::device_add_mconfig(config); + + // clocks are increased to keep up with 500 Kbps data rate of HD floppy disks + m_maincpu->set_clock(8000000); + m_fdc->set_clock(2000000); + + // external serial clock used to maintain ADAMnet rate + CLOCK(config, "clock", 500000).signal_handler().set([this] (int state) { if (state) { m_maincpu->clock_serial(); } }); + + FLOPPY_CONNECTOR(config.replace(), m_connector, adam_1440kb_floppies, "35hd", adam_fdc_mihddd_device::floppy_formats).enable_sound(true); } @@ -165,8 +277,8 @@ ioport_constructor adam_fdc_device::device_input_ports() const // adam_fdc_device - constructor //------------------------------------------------- -adam_fdc_device::adam_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, ADAM_FDC, tag, owner, clock), +adam_fdc_device::adam_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock), device_adamnet_card_interface(mconfig, *this), m_maincpu(*this, M6801_TAG), m_fdc(*this, WD2793_TAG), @@ -177,6 +289,56 @@ adam_fdc_device::adam_fdc_device(const machine_config &mconfig, const char *tag, { } +adam_fdc_device::adam_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : adam_fdc_device(mconfig, ADAM_FDC, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// adam_fdc_320kb_device - constructor +//------------------------------------------------- + +adam_fdc_320kb_device::adam_fdc_320kb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : adam_fdc_device(mconfig, type, tag, owner, clock) +{ +} + +adam_fdc_320kb_device::adam_fdc_320kb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : adam_fdc_320kb_device(mconfig, ADAM_FDC_320KB, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// adam_fdc_a720dipi_device - constructor +//------------------------------------------------- + +adam_fdc_a720dipi_device::adam_fdc_a720dipi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : adam_fdc_320kb_device(mconfig, ADAM_FDC_A720DIPI, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// adam_fdc_fp720at_device - constructor +//------------------------------------------------- + +adam_fdc_fp720at_device::adam_fdc_fp720at_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : adam_fdc_320kb_device(mconfig, ADAM_FDC_FP720AT, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// adam_fdc_mihddd_device - constructor +//------------------------------------------------- + +adam_fdc_mihddd_device::adam_fdc_mihddd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : adam_fdc_320kb_device(mconfig, ADAM_FDC_MIHDDD, tag, owner, clock) +{ +} + //------------------------------------------------- // device_start - device-specific startup @@ -265,6 +427,12 @@ uint8_t adam_fdc_device::p1_r() return data; } +uint8_t adam_fdc_a720dipi_device::p1_r() +{ + // signal inverted here because drive outputs it that way? + return adam_fdc_device::p1_r() ^ 0x01; +} + //------------------------------------------------- // p1_w - @@ -303,13 +471,27 @@ void adam_fdc_device::p1_w(uint8_t data) m_fdc->set_floppy(m_floppy); - // side select (320KB) - if (m_floppy) m_floppy->ss_w(!BIT(data, 4)); - // motor enable if (m_floppy) m_floppy->mon_w(!BIT(data, 6)); } +void adam_fdc_320kb_device::p1_w(uint8_t data) +{ + adam_fdc_device::p1_w(data); + + // side select + if (m_floppy) m_floppy->ss_w(!BIT(data, 4)); +} + +void adam_fdc_mihddd_device::p1_w(uint8_t data) +{ + // keep DDEN low here + adam_fdc_320kb_device::p1_w(data & 0xf7); + + // DD/HD select + m_fdc->enmf_w(BIT(data, 3)); +} + //------------------------------------------------- // p2_r - diff --git a/src/devices/bus/adamnet/fdc.h b/src/devices/bus/adamnet/fdc.h index 36aced31f74..1035ac6d841 100644 --- a/src/devices/bus/adamnet/fdc.h +++ b/src/devices/bus/adamnet/fdc.h @@ -32,10 +32,10 @@ public: adam_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: - // device-level overrides - virtual void device_start() override ATTR_COLD; + adam_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - // optional information overrides + // device_t overrides + virtual void device_start() override ATTR_COLD; virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; virtual ioport_constructor device_input_ports() const override ATTR_COLD; @@ -43,7 +43,6 @@ protected: // device_adamnet_card_interface overrides virtual void adamnet_reset_w(int state) override; -private: required_device<m6801_cpu_device> m_maincpu; required_device<wd2793_device> m_fdc; required_device<floppy_connector> m_connector; @@ -55,17 +54,90 @@ private: uint8_t read_data_r(offs_t offset); uint8_t write_data_r(offs_t offset); - uint8_t p1_r(); - void p1_w(uint8_t data); + virtual uint8_t p1_r(); + virtual void p1_w(uint8_t data); uint8_t p2_r(); void p2_w(uint8_t data); +private: void adam_fdc_mem(address_map &map) ATTR_COLD; }; -// device type definition +// ======================> adam_fdc_320kb_device + +class adam_fdc_320kb_device : public adam_fdc_device +{ +public: + // construction/destruction + adam_fdc_320kb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + adam_fdc_320kb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device_t overrides + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void p1_w(uint8_t data) override; +}; + + +// ======================> adam_fdc_a720dipi_device + +class adam_fdc_a720dipi_device : public adam_fdc_320kb_device +{ +public: + // construction/destruction + adam_fdc_a720dipi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device_t overrides + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual uint8_t p1_r() override; +}; + + +// ======================> adam_fdc_fp720at_device + +class adam_fdc_fp720at_device : public adam_fdc_320kb_device +{ +public: + // construction/destruction + adam_fdc_fp720at_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device_t overrides + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + + +// ======================> adam_fdc_mihddd_device + +class adam_fdc_mihddd_device : public adam_fdc_320kb_device +{ +public: + // construction/destruction + adam_fdc_mihddd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device_t overrides + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + virtual void p1_w(uint8_t data) override; +}; + + +// device type declarations DECLARE_DEVICE_TYPE(ADAM_FDC, adam_fdc_device) +DECLARE_DEVICE_TYPE(ADAM_FDC_320KB, adam_fdc_320kb_device) +DECLARE_DEVICE_TYPE(ADAM_FDC_A720DIPI, adam_fdc_a720dipi_device) +DECLARE_DEVICE_TYPE(ADAM_FDC_FP720AT, adam_fdc_fp720at_device) +DECLARE_DEVICE_TYPE(ADAM_FDC_MIHDDD, adam_fdc_mihddd_device) #endif // MAME_BUS_ADAMNET_FDC_H diff --git a/src/lib/formats/adam_dsk.cpp b/src/lib/formats/adam_dsk.cpp index 0f8dd81556c..fce713249d5 100644 --- a/src/lib/formats/adam_dsk.cpp +++ b/src/lib/formats/adam_dsk.cpp @@ -1,16 +1,99 @@ // license:BSD-3-Clause -// copyright-holders:Curt Coder -/********************************************************************* +// copyright-holders:AJR +/*************************************************************************** - formats/adam_dsk.cpp + Coleco Adam disk image format (new implementation) - Coleco Adam disk image format + The Adam's Elementary Operating System (EOS) sees all mass storage + devices as sequences of 1024-byte blocks addressed linearly through the + ADAMnet bus. However, these blocks are actually stored on 40-track or + 80-track floppy disks in two logically consecutive 512-byte sectors. + Furthermore, logically consecutive sectors are physically non-adjacent + due to interleaving implemented at the level of the FDC MCU (the + geometry is transparent to the operating system), and different native + interleaving schemes were devised depending on the number of sectors + per track. However, .dsk images are stored using the original 8-sector + interleave (1,6,3,8,5,2,7,4) regardless of their capacity. The 3.5-inch + formats, which use 9 or 18 sectors per track, thus require a convoluted + permutation of the sectors to transform their native interleave to or + from the non-native interleave. -*********************************************************************/ + Track description for 160KB SSDD format: + 100x4e 12x00 3xf5 fe 2x00 01 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 100x4e 12x00 3xf5 fe 2x00 02 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 100x4e 12x00 3xf5 fe 2x00 03 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 100x4e 12x00 3xf5 fe 2x00 04 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 100x4e 12x00 3xf5 fe 2x00 05 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 100x4e 12x00 3xf5 fe 2x00 06 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 100x4e 12x00 3xf5 fe 2x00 07 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 100x4e 12x00 3xf5 fe 2x00 08 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 + 859x4e -#include "formats/adam_dsk.h" +***************************************************************************/ -adam_format::adam_format() : wd177x_format(formats) +#include "adam_dsk.h" + +#include "ioprocs.h" + +#include <cstring> +#include <memory> + + +namespace { + +struct format_desc +{ + uint32_t size; + uint32_t form_factor; + uint32_t variant; + uint32_t cell_size; + uint8_t track_count; + uint8_t sector_count; + uint8_t head_count; +}; + +const format_desc s_formats[] = +{ + { 163840, floppy_image::FF_525, floppy_image::SSDD, 2000, 40, 8, 1 }, + { 327680, floppy_image::FF_525, floppy_image::DSDD, 2000, 40, 8, 2 }, + { 737280, floppy_image::FF_35, floppy_image::DSDD, 2000, 80, 9, 2 }, + { 1474560, floppy_image::FF_35, floppy_image::DSHD, 1000, 80, 18, 2 }, + { 0, floppy_image::FF_UNKNOWN, 0, 0, 0, 0, 0 } +}; + +const uint8_t s_interleave_9s[9] = +{ + 0, 4, 8, 3, 7, 2, 6, 1, 5 +}; + +const uint8_t s_interleave_18s[18] = +{ + 0, 4, 8, 12, 16, 2, 6, 10, 14, + 1, 5, 9, 13, 17, 3, 7, 11, 15 +}; + +const uint8_t s_cpm_boot[8] = +{ + 0x18, 0x01, 0xe5, 0x3e, 0xc9, 0x32, 0x66, 0x00 +}; + +constexpr uint8_t ZZZZ = 0x40; // a "don't care" value + +const uint8_t s_eos_directory[0x38] = +{ + 0x55, 0xaa, 0x00, 0xff, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, // magic numbers required by EOS + 'B', 'O', 'O', 'T', 0x03, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, + ZZZZ, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, ZZZZ, ZZZZ, ZZZZ, ZZZZ, ZZZZ, // covers block 0 and only block 0 + 'D', 'I', 'R', 'E', 'C', 'T', 'O', 'R', 'Y', 0x03, ZZZZ, ZZZZ, + ZZZZ, 0x01, 0x00, 0x00, 0x00 // begins with block 1 +}; + +} // anonymous namespace + + +const adam_format FLOPPY_ADAM_FORMAT; + +adam_format::adam_format() { } @@ -29,45 +112,249 @@ const char *adam_format::extensions() const noexcept return "dsk"; } -const adam_format::format adam_format::formats[] = { - // track description - // 100x4e 12x00 3xf5 fe 2x00 01 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 100x4e 12x00 3xf5 fe 2x00 02 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 100x4e 12x00 3xf5 fe 2x00 03 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 100x4e 12x00 3xf5 fe 2x00 04 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 100x4e 12x00 3xf5 fe 2x00 05 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 100x4e 12x00 3xf5 fe 2x00 06 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 100x4e 12x00 3xf5 fe 2x00 07 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 100x4e 12x00 3xf5 fe 2x00 08 02 f7 22x4e 12x00 3xf5 fb 512xe5 f7 - // 859x4e - { /* 160K 5 1/4 inch double density single sided */ - floppy_image::FF_525, floppy_image::SSDD, floppy_image::MFM, - 2000, 8, 40, 1, 512, {}, 1, {}, 100, 22, 100 - }, - - // Unverified gap sizes --> - { /* 320K 5 1/4 inch double density */ - floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM, - 2000, 8, 40, 2, 512, {}, 1, {}, 100, 22, 84 - }, - { /* 640K 5 1/4 inch quad density */ - floppy_image::FF_525, floppy_image::DSQD, floppy_image::MFM, - 2000, 8, 80, 2, 512, {}, 1, {}, 100, 22, 84 - }, - { /* 720K 3 1/2 inch double density */ - floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, - 2000, 9, 80, 2, 512, {}, 1, {}, 100, 22, 84 - }, - { /* 1440K 3 1/2 inch high density */ - floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM, - 1000, 18, 80, 2, 512, {}, 1, {}, 100, 22, 84 - }, - {} -}; +bool adam_format::supports_save() const noexcept +{ + return true; +} + +int adam_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + uint64_t size; + if (io.length(size)) + return 0; + + // Size must match exactly + const format_desc *f = &s_formats[0]; + while (f->size != size) + { + if (!(++f)->size) + return 0; + } -int adam_format::get_image_offset(const format &f, int head, int track) const + // Form factor and variant must agree if provided + if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f->form_factor) + return 0; + if (!variants.empty() && !has_variant(variants, f->variant)) + return 0; + + // Size confirmed; now do a little extra work to confirm presence of Adam data + // (since .dsk extension is shared by a lot of formats for other systems) + + // First, check for the beginning of a standalone bootloader commonly used on CP/M disks + std::uint8_t buffer[0x38]; + auto const [err, actual] = read_at(io, 0, &buffer[0], 8); + if (!err && actual == 8 && !std::memcmp(&buffer[0], s_cpm_boot, 8)) + return FIFID_SIZE | FIFID_HINT; + + // EOS bootloaders are varied enough that checking for their system calls is annoying inefficient + // Instead, check in block 1 for the magic signature and the special BOOT and DIRECTORY entries + // (which some CP/M disks also have as part of a fake directory structure) + auto const [err2, actual2] = read_at(io, 0x40d, &buffer[0], 0x38); + if (!err2 && actual2 == 0x38) + { + int i = 0; + while (i < 0x38 && (s_eos_directory[i] == ZZZZ || s_eos_directory[i] == buffer[i])) + i++; + if (i == 0x38) + return FIFID_SIZE | FIFID_HINT; + } + + return FIFID_SIZE; +} + +bool adam_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - return (track + (head ? f.track_count : 0)) * compute_track_size(f); + uint64_t size; + if (io.length(size)) + return false; + + // Find the size that matches + const format_desc *f = &s_formats[0]; + while (f->size != size) + { + if (!(++f)->size) + return false; + } + + // Verify that the geometry will fit + int max_tracks, max_heads; + image.get_maximal_geometry(max_tracks, max_heads); + if (f->track_count > max_tracks || f->head_count > max_heads) + return false; + + const int track_size = f->sector_count * 512; + const auto track_data = std::make_unique<uint8_t []>(track_size); + desc_pc_sector sector_desc[18]; + + const uint32_t cell_count = 200000000 / f->cell_size; + unsigned sector_offset = 0; + switch (f->form_factor) + { + case floppy_image::FF_525: + // Sectors are stored in native order + for (int sector = 0; sector < f->sector_count; sector++) + { + sector_desc[sector].sector = sector + 1; + sector_desc[sector].size = 2; + sector_desc[sector].actual_size = 512; + sector_desc[sector].data = &track_data[uint32_t(sector) * 512]; + sector_desc[sector].deleted = false; + sector_desc[sector].bad_crc = false; + } + + // For double-sided 5.25" images, read one side after the other + for (int head = 0; head < f->head_count; head++) + { + for (int track = 0; track < f->track_count; track++) + { + // Read in one entire track + auto const [err, actual] = read_at(io, uint32_t(sector_offset) * 512, track_data.get(), track_size); + if (err || (actual != track_size)) + return false; + + // Finish up the sector descriptions + for (int sector = 0; sector < f->sector_count; sector++) + { + sector_desc[sector].track = track; + sector_desc[sector].head = head; + } + + // Create the track + build_wd_track_mfm(track, head, image, cell_count, f->sector_count, sector_desc, 100, 100, 22); + sector_offset += f->sector_count; + } + } + break; + + case floppy_image::FF_35: + // Set up the native interleave + for (int i = 0; i < f->sector_count; i++) + { + const int sector = f->sector_count == 18 ? s_interleave_18s[i] : s_interleave_9s[i]; + sector_desc[sector].sector = sector + 1; + sector_desc[sector].size = 2; + sector_desc[sector].actual_size = 512; + sector_desc[sector].data = &track_data[uint32_t(i) * 512]; + sector_desc[sector].deleted = false; + sector_desc[sector].bad_crc = false; + } + + // For 3.5" images, tracks are interleaved between sides + for (int track = 0; track < f->track_count; track++) + { + for (int head = 0; head < f->head_count; head++) + { + for (int i = 0; i < f->sector_count; i++, sector_offset++) + { + // Apply the non-native sector interleave (5 modulo 8) + const unsigned mangled_offset = sector_offset ^ ((sector_offset & 1) << 2); + + // Read in one sector at a time + auto const [err, actual] = read_at(io, uint32_t(mangled_offset) * 512, &track_data[uint32_t(i) * 512], 512); + if (err || (actual != 512)) + return false; + + // Also finish up the sector descriptions + sector_desc[i].track = track; + sector_desc[i].head = head; + } + + // Create the track (TODO: verify gap sizes) + build_wd_track_mfm(track, head, image, cell_count, f->sector_count, sector_desc, 84, 100, 22); + } + } + break; + + default: + // Never happens + return false; + } + + // Assign the form factor and variant + image.set_form_variant(f->form_factor, f->variant); + + // Success + return true; } -const adam_format FLOPPY_ADAM_FORMAT; +bool adam_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const +{ + int tracks, heads; + image.get_actual_geometry(tracks, heads); + + // Find an appropriate format + const format_desc *f = &s_formats[0]; + while (f->form_factor != image.get_form_factor() || f->variant != image.get_variant() + || f->track_count > tracks || f->head_count > heads) + { + if (!(++f)->size) + return false; + } + + unsigned sector_offset = 0; + switch (f->form_factor) + { + case floppy_image::FF_525: + for (int head = 0; head < f->head_count; head++) + { + for (int track = 0; track < f->track_count; track++) + { + // Extract the sectors for each track + const auto bitstream = generate_bitstream_from_track(track, head, f->cell_size, image); + const auto sectors = extract_sectors_from_bitstream_mfm_pc(bitstream); + if (sectors.size() > f->sector_count + 1) + return false; + + for (int sector = 1; sector <= f->sector_count; sector++, sector_offset++) + { + const auto &s = sectors[sector]; + if (s.size() != 512) + return false; + + // Write each sector in sequence + auto const [err, actual] = write_at(io, uint32_t(sector_offset) * 512, s.data(), 512); + if (err || (actual != 512)) + return false; + } + } + } + break; + + case floppy_image::FF_35: + for (int track = 0; track < f->track_count; track++) + { + for (int head = 0; head < f->head_count; head++) + { + // Extract the sectors for each track + const auto bitstream = generate_bitstream_from_track(track, head, f->cell_size, image); + const auto sectors = extract_sectors_from_bitstream_mfm_pc(bitstream); + if (sectors.size() > f->sector_count + 1) + return false; + + for (int i = 0; i < f->sector_count; i++, sector_offset++) + { + // Resolve the native interleave + const auto &s = sectors[(f->sector_count == 18 ? s_interleave_18s[i] : s_interleave_9s[i]) + 1]; + if (s.size() != 512) + return false; + + // Apply the non-native sector interleave (5 modulo 8) + const unsigned mangled_offset = sector_offset ^ ((sector_offset & 1) << 2); + + // Write each sector + auto const [err, actual] = write_at(io, uint32_t(mangled_offset) * 512, s.data(), 512); + if (err || (actual != 512)) + return false; + } + } + } + break; + + default: + // Never happens + return false; + } + + // Success at last + return true; +} diff --git a/src/lib/formats/adam_dsk.h b/src/lib/formats/adam_dsk.h index 36982ac02bd..f5bb73af65a 100644 --- a/src/lib/formats/adam_dsk.h +++ b/src/lib/formats/adam_dsk.h @@ -1,20 +1,14 @@ // license:BSD-3-Clause -// copyright-holders:Curt Coder -/********************************************************************* +// copyright-holders:AJR - formats/adam_dsk.h - - Coleco Adam disk image format - -*********************************************************************/ #ifndef MAME_FORMATS_ADAM_DSK_H #define MAME_FORMATS_ADAM_DSK_H #pragma once -#include "wd177x_dsk.h" +#include "flopimg.h" -class adam_format : public wd177x_format +class adam_format : public floppy_image_format_t { public: adam_format(); @@ -22,11 +16,11 @@ public: virtual const char *name() const noexcept override; virtual const char *description() const noexcept override; virtual const char *extensions() const noexcept override; + virtual bool supports_save() const noexcept override; - virtual int get_image_offset(const format &f, int head, int track) const override; - -private: - static const format formats[]; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const override; }; extern const adam_format FLOPPY_ADAM_FORMAT; diff --git a/src/mame/coleco/adam.cpp b/src/mame/coleco/adam.cpp index f21effdfd67..cabfe98527c 100644 --- a/src/mame/coleco/adam.cpp +++ b/src/mame/coleco/adam.cpp @@ -1036,7 +1036,12 @@ void adam_state::adam(machine_config &config) ADAMNET_SLOT(config, "net2", m_adamnet, adamnet_devices, "prn"); ADAMNET_SLOT(config, "net3", m_adamnet, adamnet_devices, "ddp"); ADAMNET_SLOT(config, "net4", m_adamnet, adamnet_devices, "fdc"); - ADAMNET_SLOT(config, "net5", m_adamnet, adamnet_devices, "fdc").set_option_device_input_defaults("fdc", device_iptdef_drive2); + adamnet_slot_device &net5(ADAMNET_SLOT(config, "net5", m_adamnet, adamnet_devices, "fdc")); + net.set_option_device_input_defaults("fdc", device_iptdef_drive2); + net.set_option_device_input_defaults("fdc_320kb", device_iptdef_drive2); + net.set_option_device_input_defaults("fdc_a720dipi", device_iptdef_drive2); + net.set_option_device_input_defaults("fdc_fp720at", device_iptdef_drive2); + net.set_option_device_input_defaults("fdc_mihddd", device_iptdef_drive2); ADAMNET_SLOT(config, "net6", m_adamnet, adamnet_devices, nullptr); ADAMNET_SLOT(config, "net7", m_adamnet, adamnet_devices, nullptr); ADAMNET_SLOT(config, "net8", m_adamnet, adamnet_devices, nullptr); |
