diff --git a/src/lib/formats/flex_dsk.cpp b/src/lib/formats/flex_dsk.cpp index fb7dfb1499b..30ff15dcf74 100644 --- a/src/lib/formats/flex_dsk.cpp +++ b/src/lib/formats/flex_dsk.cpp @@ -4,12 +4,21 @@ * flex_dsk.c - FLEX compatible disk images * * Created on: 24/06/2014 + * + * TODO This format does not yet handle double density disks with a single + * density track 0. FLEX DSK files are generally 'fixed' to have a consistent + * number of sectors per track which makes them easier to work with and gains + * more storage space, and tools and emulators generally only work with these + * formats. For now use single density disks, or patch the ROM to load the + * boot sector(s) in double density and patch the drivers to use double + * density on track zero. Drivers developed for emulators commonly have other + * issues and need work anyway. */ - #include "emu.h" // logerror #include "flex_dsk.h" +#include "formats/imageutl.h" -flex_format::flex_format() +flex_format::flex_format() : wd177x_format(formats) { } @@ -28,80 +37,310 @@ const char *flex_format::extensions() const return "dsk"; } -bool flex_format::supports_save() const -{ - return true; -} - int flex_format::identify(io_generic *io, uint32_t form_factor) { - io_generic_read(io, &info, 256 * 2, sizeof(struct sysinfo_sector)); + int type = find_size(io, form_factor); - if(((info.last_trk+1) * info.last_sec) * 256 == io_generic_size(io)) - { - osd_printf_verbose("flex_dsk: %i tracks, %i sectors\n",info.last_trk+1,info.last_sec); - return 100; - } + if (type != -1) + return 75; return 0; } -bool flex_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) +int flex_format::find_size(io_generic *io, uint32_t form_factor) { - int spt = info.last_sec; - int bps = 256; - int cell_count = (form_factor == floppy_image::FF_525) ? 50000 : 100000; - int offset = 0; - int head_num = 1; - int total_tracks = info.last_trk+1; - bool double_sided = false; + uint64_t size = io_generic_size(io); + uint8_t boot0[256], boot1[256]; - if(total_tracks == 40 && spt == 36) - double_sided = true; - if(total_tracks == 77 && spt == 30) - double_sided = true; - if(total_tracks == 80 && spt == 40) // 800kB - double_sided = true; - if(total_tracks == 80 && spt == 72) // 1.44MB - double_sided = true; - if(spt >= 20) - double_sided = true; + // Look at the boot sector. + // Density, sides, link?? + io_generic_read(io, &boot0, 256 * 0, sizeof(boot0)); + io_generic_read(io, &boot1, 256 * 1, sizeof(boot1)); + // Look at the system information sector. + io_generic_read(io, &info, 256 * 2, sizeof(struct sysinfo_sector)); - if(double_sided) - { - spt = spt / 2; - head_num = 2; + LOG_FORMATS("FLEX floppy dsk size %d %d %d\n", (uint32_t)size, (uint32_t)size / 256, (uint32_t)size % 256); + + LOG_FORMATS(" boot0:"); + for (int i = 0; i < 16; i++) { + LOG_FORMATS(" %02x", boot0[i]); } + LOG_FORMATS("\n"); - for(int track=0; track < total_tracks; track++) - for(int head=0;head < head_num;head++) + LOG_FORMATS(" boot1:"); + for (int i = 0; i < 16; i++) { + LOG_FORMATS(" %02x", boot1[i]); + } + LOG_FORMATS("\n"); + + + // Check that the 'unused' area is actually unused. + LOG_FORMATS(" unused1:"); + for (int i = 0; i < sizeof(info.unused1); i++) { + LOG_FORMATS(" %02x", info.unused1[i]); + } + LOG_FORMATS("\n"); + + LOG_FORMATS(" disk_name: \""); + for (int i = 0; i < sizeof(info.disk_name); i++) { + uint8_t ch = info.disk_name[i]; + if (ch < 0x20 || ch > 0x7f) { + LOG_FORMATS("[%02x]", ch); + } else { + LOG_FORMATS("%c", ch); + } + } + if (info.disk_ext[0] || info.disk_ext[1] || info.disk_ext[2]) { + LOG_FORMATS("."); + for (int i = 0; i < sizeof(info.disk_name); i++) { + uint8_t ch = info.disk_name[i]; + if (ch < 0x20 || ch > 0x7f) { + LOG_FORMATS("[%02x]", ch); + } else { + LOG_FORMATS("%c", ch); + } + } + } + LOG_FORMATS("\"\n"); + + LOG_FORMATS(" fc_start_trk %d, fc_start_sec %d\n", info.fc_start_trk, info.fc_start_sec); + LOG_FORMATS(" fc_end_trk: %d, fc_end_sec: %d\n", info.fc_end_trk, info.fc_end_sec); + LOG_FORMATS(" free: %02x %02x\n", info.free[0], info.free[0]); + + LOG_FORMATS(" month %d day %d year %d\n", info.month, info.day, info.year); + LOG_FORMATS(" last_trk %d, last_sec %d\n", info.last_trk, info.last_sec); + + LOG_FORMATS(" unused2:"); + for (int i = 0; i < 16; i++) { + LOG_FORMATS(" %02x", info.unused2[i]); + } + LOG_FORMATS("\n"); + +#if 0 + // Check that the first 'unused' area is zero filled. + // Unfortunately an occasional dsk image has non-zero values here. + for (int i = 0; i < sizeof(info.unused1); i++) + if (info.unused1[i] != 0) return -1; +#endif + + // Consistency checks. + if (info.fc_start_trk > info.last_trk || info.fc_end_trk > info.last_trk) + return -1; + if (info.fc_start_sec > info.last_sec || info.fc_end_sec > info.last_sec) + return -1; + if (info.month < 1 || info.month > 12 || info.day < 1 || info.day > 31) + return -1; + + // FLEX sector numbers start at one generally, however the 6800 ROM + // boot loaders load the boot code from track zero, side zero, + // starting at sector zero. The boot code attempts to read multiple + // sectors and a gap in the sector numbering appears to be used to + // terminate the sequence. So if only one sector is to be loaded then + // the sector numbering is 0, 2, 3, .... If two sectors are to be + // loaded then the sector numbering is 0, 1, 3, 4 ... The boot loaders + // for 6809 FLEX systems appear to load from sector one so do not have + // this inconsistency to handle. + boot0_sector_id = 1; + boot1_sector_id = 2; + + // This floppy format uses a strategy of looking for 6800 boot code to + // set the numbering of the first two sectors. If this is shown to not + // be practical in some common cases then a separate format variant + // might be needed. + if (boot0[0] == 0x8e && boot0[3] == 0x20) + { + // Found a 6800 stack load and branch, looks like a 6800 boot sector. + boot0_sector_id = 0; + + // Look for a link to the next sector, normal usage. + if (boot1[0] != 0 || boot1[1] != 3) { - desc_pc_sector sects[80]; - uint8_t sect_data[20000]; - int sdatapos = 0; - for(int i=0; i= 1 && track <= 2)) // handle Gimix Flex 3.6 disk image, which the boot sector loads tracks 1 and 2 as MFM - build_wd_track_mfm(track, head, image, cell_count*2, spt, sects, 50, 32, 22); - else - build_wd_track_fm(track, head, image, cell_count, spt, sects, 24, 16, 11); + // If not then assume it is a boot sector. + boot1_sector_id = 1; } - return true; + } + LOG_FORMATS(" boot sector ids: %d %d\n", boot0_sector_id, boot1_sector_id); + + for(int i=0; formats[i].form_factor; i++) { + const format &f = formats[i]; + if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) + continue; + + if(size != (uint64_t)compute_track_size(f) * f.track_count * f.head_count) + continue; + + // Check consistency with the sysinfo record sector. + if (f.track_count != info.last_trk + 1) + continue; + + if (f.sector_count * f.head_count != info.last_sec) + continue; + + return i; + } + return -1; } +// FLEX numbers sectors on the second side of a track continuing from the +// first side which is a variation not handled by the generic code. +// +// FLEX generally numbers sectors starting at 1, however the 6800 boot sectors +// are numbers starting at zero. +// +void flex_format::build_sector_description(const format &f, uint8_t *sectdata, desc_s *sectors, int track, int head) const +{ + if(f.sector_base_id == -1) { + for(int i=0; i &candidates) +{ + uint8_t bitstream[500000/8]; + uint8_t sectdata[50000]; + desc_xs sectors[256]; + int track_size; + + // Extract the sectors + generate_bitstream_from_track(1, 0, formats[candidates[0]].cell_size, bitstream, track_size, image); + + switch (formats[candidates[0]].encoding) + { + case floppy_image::FM: + extract_sectors_from_bitstream_fm_pc(bitstream, track_size, sectors, sectdata, sizeof(sectdata)); + break; + case floppy_image::MFM: + extract_sectors_from_bitstream_mfm_pc(bitstream, track_size, sectors, sectdata, sizeof(sectdata)); + break; + } + + // Check compatibility with every candidate, copy in-place + int *ok_cands = &candidates[0]; + for(unsigned int i=0; i != candidates.size(); i++) { + const format &f = formats[candidates[i]]; + int ns = 0; + for(int j=0; j<256; j++) + if(sectors[j].data) { + int sid; + if(f.sector_base_id == -1) { + for(sid=0; sid < f.sector_count; sid++) + if(f.per_sector_id[sid] == j) + break; + } else + sid = j - f.sector_base_id; + if(sid < 0 || sid > f.sector_count) + goto fail; + if(f.sector_base_size) { + if(sectors[j].size != f.sector_base_size) + goto fail; + } else { + if(sectors[j].size != f.per_sector_size[sid]) + goto fail; + } + ns++; + } + if(ns == f.sector_count) + *ok_cands++ = candidates[i]; + fail: + ; + } + candidates.resize(ok_cands - &candidates[0]); +} + +const flex_format::format flex_format::formats[] = { + { // 87.5K 5 1/4 inch single density - gaps unverified + floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM, + 4000, 10, 35, 1, 256, {}, 1, {}, 40, 16, 11 + }, + { // 100K 5 1/4 inch single density - gaps unverified + floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM, + 4000, 10, 40, 1, 256, {}, 1, {}, 40, 16, 11 + }, + { // 200K 5 1/4 inch single density - gaps unverified + floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM, + 4000, 10, 80, 1, 256, {}, 1, {}, 40, 16, 11 + }, + { // 175K 5 1/4 inch single density - gaps unverified + floppy_image::FF_525, floppy_image::DSSD, floppy_image::FM, + 4000, 10, 35, 2, 256, {}, 1, {}, 40, 16, 11 + }, + { // 200K 5 1/4 inch single density - gaps unverified + floppy_image::FF_525, floppy_image::DSSD, floppy_image::FM, + 4000, 10, 40, 2, 256, {}, 1, {}, 40, 16, 11 + }, + { // 400K 5 1/4 inch single density - gaps unverified + floppy_image::FF_525, floppy_image::DSSD, floppy_image::FM, + 4000, 10, 80, 2, 256, {}, 1, {}, 40, 16, 11 + }, + { // 320K 5 1/4 inch double density - gaps unverified + floppy_image::FF_525, floppy_image::SSDD, floppy_image::MFM, + 2000, 18, 40, 1, 256, {}, 1, {}, 80, 22, 24 + }, + { // 320K 5 1/4 inch double density - gaps unverified + floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM, + 2000, 18, 40, 2, 256, {}, 1, {}, 80, 22, 24 + }, + { // 360K 5 1/4 inch quad density - gaps unverified + floppy_image::FF_525, floppy_image::SSQD, floppy_image::MFM, + 2000, 18, 80, 1, 256, {}, 1, {}, 80, 22, 24 + }, + { // 720K 5 1/4 inch quad density - gaps unverified + floppy_image::FF_525, floppy_image::DSQD, floppy_image::MFM, + 2000, 18, 80, 2, 256, {}, 1, {}, 80, 22, 24 + }, + { // 288.75K 8 inch single density - gaps unverified + floppy_image::FF_8, floppy_image::SSSD, floppy_image::FM, + 2000, 15, 77, 1, 256, {}, 1, {}, 40, 12, 12 + }, + { // 577.5K 8 inch single density - gaps unverified + floppy_image::FF_8, floppy_image::DSSD, floppy_image::FM, + 2000, 15, 77, 2, 256, {}, 1, {}, 40, 12, 12 + }, + { // 500.5K 8 inch double density - gaps unverified + floppy_image::FF_8, floppy_image::SSDD, floppy_image::MFM, + 1000, 26, 77, 1, 256, {}, 1, {}, 80, 22, 24 + }, + { // 1001K 8 inch double density - gaps unverified + floppy_image::FF_8, floppy_image::DSDD, floppy_image::MFM, + 1000, 26, 77, 2, 256, {}, 1, {}, 80, 22, 24 + }, + { /* 1440K 3 1/2 inch high density */ + floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM, + 1000, 36, 80, 2, 256, {}, 1, {}, 80, 22, 24 + }, + {} +}; + const floppy_format_type FLOPPY_FLEX_FORMAT = &floppy_image_format_creator; diff --git a/src/lib/formats/flex_dsk.h b/src/lib/formats/flex_dsk.h index 7e2f7c3d8e3..3c61bdd4243 100644 --- a/src/lib/formats/flex_dsk.h +++ b/src/lib/formats/flex_dsk.h @@ -11,8 +11,9 @@ #pragma once #include "flopimg.h" +#include "wd177x_dsk.h" -class flex_format : public floppy_image_format_t +class flex_format : public wd177x_format { public: flex_format(); @@ -21,8 +22,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; virtual int identify(io_generic *io, uint32_t form_factor) override; - virtual bool load(io_generic *io, uint32_t form_factor, floppy_image *image) override; - virtual bool supports_save() const override; + virtual int find_size(io_generic *io, uint32_t form_factor) override; + virtual void build_sector_description(const format &f, uint8_t *sectdata, desc_s *sectors, int track, int head) const override; + virtual void check_compatibility(floppy_image *image, std::vector &candidates) override; private: struct sysinfo_sector @@ -43,6 +45,10 @@ private: uint8_t last_sec; uint8_t unused2[216]; } info; + static const format formats[]; + + uint8_t boot0_sector_id; + uint8_t boot1_sector_id; }; extern const floppy_format_type FLOPPY_FLEX_FORMAT; diff --git a/src/lib/formats/wd177x_dsk.h b/src/lib/formats/wd177x_dsk.h index 1843fcdf0a2..95431b3aaaa 100644 --- a/src/lib/formats/wd177x_dsk.h +++ b/src/lib/formats/wd177x_dsk.h @@ -57,7 +57,7 @@ protected: int compute_track_size(const format &f) const; virtual void build_sector_description(const format &d, uint8_t *sectdata, desc_s *sectors, int track, int head) const; - void check_compatibility(floppy_image *image, std::vector &candidates); + virtual void check_compatibility(floppy_image *image, std::vector &candidates); void extract_sectors(floppy_image *image, const format &f, desc_s *sdesc, int track, int head); };