From 66c0222c690fb6fb0e093fad37d42a68fea66a2f Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Fri, 25 Mar 2022 09:25:16 +0100 Subject: [PATCH] hfe: Remove write support for now, it has issues (sharing data between read and write, copy/pasting the pll code, not supporting v3). May be rewritten once the other changes are in --- src/lib/formats/hxchfe_dsk.cpp | 385 ++++----------------------------- src/lib/formats/hxchfe_dsk.h | 42 ++-- 2 files changed, 64 insertions(+), 363 deletions(-) diff --git a/src/lib/formats/hxchfe_dsk.cpp b/src/lib/formats/hxchfe_dsk.cpp index 9c94b1833a4..e1c5b08cb8b 100644 --- a/src/lib/formats/hxchfe_dsk.cpp +++ b/src/lib/formats/hxchfe_dsk.cpp @@ -111,21 +111,7 @@ #define HEADER_LENGTH 512 #define TRACK_TABLE_LENGTH 1024 -hfe_format::hfe_format() : floppy_image_format_t(), - m_cylinders(0), - m_heads(0), - m_track_encoding(UNKNOWN_ENCODING), - m_bit_rate(0), - m_floppy_rpm(0), - m_interface_mode(DISABLE_FLOPPYMODE), - m_write_allowed(true), - m_single_step(true), - m_track0s0_has_altencoding(false), - m_track0s0_encoding(UNKNOWN_ENCODING), - m_track0s1_has_altencoding(false), - m_track0s1_encoding(UNKNOWN_ENCODING), - m_selected_mode(DISABLE_FLOPPYMODE), - m_selected_encoding(UNKNOWN_ENCODING) +hfe_format::hfe_format() : floppy_image_format_t() { } @@ -146,7 +132,7 @@ const char *hfe_format::extensions() const bool hfe_format::supports_save() const { - return true; + return false; } int hfe_format::identify(util::random_read &io, uint32_t form_factor, const std::vector &variants) @@ -166,6 +152,7 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve size_t actual; uint8_t header[HEADER_LENGTH]; uint8_t track_table[TRACK_TABLE_LENGTH]; + header_info info; int drivecyl, driveheads; image->get_maximal_geometry(drivecyl, driveheads); @@ -181,101 +168,101 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve return false; } - m_cylinders = header[9] & 0xff; - m_heads = header[10] & 0xff; + info.m_cylinders = header[9] & 0xff; + info.m_heads = header[10] & 0xff; - if (drivecyl < m_cylinders) + if (drivecyl < info.m_cylinders) { - if (m_cylinders - drivecyl > DUMP_THRESHOLD) + if (info.m_cylinders - drivecyl > DUMP_THRESHOLD) { - osd_printf_error("hxchfe: Floppy disk has too many tracks for this drive (floppy tracks=%d, drive tracks=%d).\n", m_cylinders, drivecyl); + osd_printf_error("hxchfe: Floppy disk has too many tracks for this drive (floppy tracks=%d, drive tracks=%d).\n", info.m_cylinders, drivecyl); return false; } else { // Some dumps has a few excess tracks to be safe, // lets be nice and just skip those tracks - osd_printf_warning("hxchfe: Floppy disk has a slight excess of tracks for this drive that will be discarded (floppy tracks=%d, drive tracks=%d).\n", m_cylinders, drivecyl); - m_cylinders = drivecyl; + osd_printf_warning("hxchfe: Floppy disk has a slight excess of tracks for this drive that will be discarded (floppy tracks=%d, drive tracks=%d).\n", info.m_cylinders, drivecyl); + info.m_cylinders = drivecyl; } } - if (m_cylinders <= drivecyl/2) + if (info.m_cylinders <= drivecyl/2) { - osd_printf_error("hxchfe: Double stepping not yet supported (floppy tracks=%d, drive tracks=%d).\n", m_cylinders, drivecyl); + osd_printf_error("hxchfe: Double stepping not yet supported (floppy tracks=%d, drive tracks=%d).\n", info.m_cylinders, drivecyl); return false; } - m_track_encoding = (encoding_t)(header[11] & 0xff); + info.m_track_encoding = (encoding_t)(header[11] & 0xff); - if (m_track_encoding > EMU_FM_ENCODING) + if (info.m_track_encoding > EMU_FM_ENCODING) { - osd_printf_error("hxchfe: Unknown track encoding %d.\n", m_track_encoding); + osd_printf_error("hxchfe: Unknown track encoding %d.\n", info.m_track_encoding); return false; } - m_bit_rate = (header[12] & 0xff) | ((header[13] & 0xff)<<8); + info.m_bit_rate = (header[12] & 0xff) | ((header[13] & 0xff)<<8); - if (m_bit_rate > 500) + if (info.m_bit_rate > 500) { - osd_printf_error("hxchfe: Unsupported bit rate %d.\n", m_bit_rate); + osd_printf_error("hxchfe: Unsupported bit rate %d.\n", info.m_bit_rate); return false; } - int samplelength = 500000 / m_bit_rate; + int samplelength = 500000 / info.m_bit_rate; // Not used in the HxC emulator - m_floppy_rpm = (header[14] & 0xff) | ((header[15] & 0xff)<<8); + info.m_floppy_rpm = (header[14] & 0xff) | ((header[15] & 0xff)<<8); - m_interface_mode = (floppymode_t)(header[16] & 0xff); - if (m_interface_mode > S950_HD_FLOPPYMODE) + info.m_interface_mode = (floppymode_t)(header[16] & 0xff); + if (info.m_interface_mode > S950_HD_FLOPPYMODE) { - osd_printf_error("hxchfe: Unknown interface mode %d.\n", m_interface_mode); + osd_printf_error("hxchfe: Unknown interface mode %d.\n", info.m_interface_mode); return false; } - m_write_allowed = (header[20] != 0); - m_single_step = (header[21] != 0); - m_track0s0_has_altencoding = (header[22] == 0x00); - m_track0s0_encoding = (encoding_t)(header[23] & 0xff); - m_track0s1_has_altencoding = (header[24] == 0x00); - m_track0s1_encoding = (encoding_t)(header[25] & 0xff); + info.m_write_allowed = (header[20] != 0); + info.m_single_step = (header[21] != 0); + info.m_track0s0_has_altencoding = (header[22] == 0x00); + info.m_track0s0_encoding = (encoding_t)(header[23] & 0xff); + info.m_track0s1_has_altencoding = (header[24] == 0x00); + info.m_track0s1_encoding = (encoding_t)(header[25] & 0xff); // read track lookup table (multiple of 512) int table_offset = (header[18] & 0xff) | ((header[19] & 0xff)<<8); io.read_at(table_offset<<9, track_table, TRACK_TABLE_LENGTH, actual); - for (int i=0; i < m_cylinders; i++) + for (int i=0; i < info.m_cylinders; i++) { - m_cyl_offset[i] = (track_table[4*i] & 0xff) | ((track_table[4*i+1] & 0xff)<<8); - m_cyl_length[i] = (track_table[4*i+2] & 0xff) | ((track_table[4*i+3] & 0xff)<<8); + info.m_cyl_offset[i] = (track_table[4*i] & 0xff) | ((track_table[4*i+1] & 0xff)<<8); + info.m_cyl_length[i] = (track_table[4*i+2] & 0xff) | ((track_table[4*i+3] & 0xff)<<8); } // Load the tracks std::vector cylinder_buffer; - for(int cyl=0; cyl < m_cylinders; cyl++) + for(int cyl=0; cyl < info.m_cylinders; cyl++) { // actual data read // The HFE format defines an interleave of the two sides per cylinder // at every 256 bytes - cylinder_buffer.resize(m_cyl_length[cyl]); - io.read_at(m_cyl_offset[cyl]<<9, &cylinder_buffer[0], m_cyl_length[cyl], actual); + cylinder_buffer.resize(info.m_cyl_length[cyl]); + io.read_at(info.m_cyl_offset[cyl]<<9, &cylinder_buffer[0], info.m_cyl_length[cyl], actual); - generate_track_from_hfe_bitstream(cyl, 0, samplelength, &cylinder_buffer[0], m_cyl_length[cyl], image); - if (m_heads == 2) - generate_track_from_hfe_bitstream(cyl, 1, samplelength, &cylinder_buffer[0], m_cyl_length[cyl], image); + generate_track_from_hfe_bitstream(cyl, 0, samplelength, &cylinder_buffer[0], info.m_cyl_length[cyl], image); + if (info.m_heads == 2) + generate_track_from_hfe_bitstream(cyl, 1, samplelength, &cylinder_buffer[0], info.m_cyl_length[cyl], image); } bool success = true; // Find variant - if (m_track_encoding == ISOIBM_FM_ENCODING || m_track_encoding == EMU_FM_ENCODING) + if (info.m_track_encoding == ISOIBM_FM_ENCODING || info.m_track_encoding == EMU_FM_ENCODING) // FM is for single density - image->set_variant((m_heads==1)? floppy_image::SSSD : floppy_image::DSSD); + image->set_variant((info.m_heads==1)? floppy_image::SSSD : floppy_image::DSSD); else { // MFM encoding is for everything else - if (m_track_encoding == ISOIBM_MFM_ENCODING || m_track_encoding == AMIGA_MFM_ENCODING) + if (info.m_track_encoding == ISOIBM_MFM_ENCODING || info.m_track_encoding == AMIGA_MFM_ENCODING) { // Each cylinder contains the samples of both sides, 8 samples per // byte; the bitRate determines how many samples constitute a cell @@ -286,7 +273,7 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve // DSED: 2.8 MiB = 2*80*36*512 bytes; 400000 cells/track, 500 ns, 1 Mbit/s // Use cylinder 1 (cyl 0 may have special encodings) - int cellcount = (m_cyl_length[1] * 8 / 2) * 250 / m_bit_rate; + int cellcount = (info.m_cyl_length[1] * 8 / 2) * 250 / info.m_bit_rate; if (cellcount > 300000) image->set_variant(floppy_image::DSED); else @@ -297,7 +284,7 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve { if (cellcount > 90000) // We cannot distinguish DSDD from DSQD without knowing the size of the floppy disk - image->set_variant((m_heads==1)? floppy_image::SSDD : floppy_image::DSDD); + image->set_variant((info.m_heads==1)? floppy_image::SSDD : floppy_image::DSDD); } } } @@ -419,292 +406,6 @@ void hfe_format::generate_track_from_hfe_bitstream(int cyl, int head, int sample image->set_write_splice_position(cyl, head, 0, 0); } -bool hfe_format::save(util::random_read_write &io, const std::vector &variants, floppy_image *image) -{ - size_t actual; - std::vector cylbuf; - - // Create a buffer that is big enough to handle HD formats. We don't - // know the track length until we generate the HFE bitstream. - cylbuf.resize(0x10000); - - uint8_t header[HEADER_LENGTH]; - uint8_t track_table[TRACK_TABLE_LENGTH]; - - int track_end = 0x61c0; - int samplelength = 2000; - - // Set up header - const char* sig = "HXCPICFE"; - memcpy(header, sig, 8); - - header[8] = 0; - // Can we change the number of tracks or heads? - image->get_actual_geometry(m_cylinders, m_heads); - - header[9] = m_cylinders; - header[10] = m_heads; - // Floppy RPM is not used - header[14] = 0; - header[15] = 0; - - // Bit rate and encoding will be set later, they may have changed by - // reformatting. The selected encoding is UNKNOWN_ENCODING unless - // explicitly set - m_track_encoding = m_selected_encoding; - - // Take the old mode, unless we have specified a mode - header[16] = (m_selected_mode != DISABLE_FLOPPYMODE)? m_selected_mode : m_interface_mode; - header[17] = 0; - - // The track lookup table is located at offset 0x200 (as 512 multiple) - header[18] = 1; - header[19] = 0; - - header[20] = m_write_allowed? 0xff : 0x00; - header[21] = m_single_step? 0xff : 0x00; - - // TODO: Allow for divergent track 0 format - header[22] = m_track0s0_has_altencoding? 0x00 : 0xff; - header[23] = m_track0s0_encoding; - header[24] = m_track0s1_has_altencoding? 0x00 : 0xff; - header[25] = m_track0s1_encoding; - - // Fill the remaining bytes with 0xff - for (int i=26; i < HEADER_LENGTH; i++) header[i] = 0xff; - - // Don't write yet; we still have to find out the bit rate. - - // We won't have more than 200000 cells on the track - for (int cyl=0; cyl < m_cylinders; cyl++) - { - // After the call, the encoding will be set to FM or MFM - generate_hfe_bitstream_from_track(cyl, 0, samplelength, m_track_encoding, &cylbuf[0], track_end, image); - if (m_heads == 2) - generate_hfe_bitstream_from_track(cyl, 1, samplelength, m_track_encoding, &cylbuf[0], track_end, image); - - if (cyl==0) - { - // Complete the header and write it - header[11] = m_track_encoding; - m_bit_rate = 500000/samplelength; - header[12] = m_bit_rate & 0xff; - header[13] = (m_bit_rate >> 8) & 0xff; - - // Now write the header - io.write_at(0, header, HEADER_LENGTH, actual); - - // Set up the track lookup table - // We need the encoding value to be sure about the track length - int len = (m_track_encoding==ISOIBM_FM_ENCODING)? 0x61b0 : 0x61c0; - int pos = 0x400; - - for (int i=0; i < m_cylinders; i++) - { - m_cyl_offset[i] = (pos >> 9); - m_cyl_length[i] = len; - pos += (len + 0x1ff) & 0xfe00; - track_table[i*4] = m_cyl_offset[i] & 0xff; - track_table[i*4+1] = (m_cyl_offset[i]>>8) & 0xff; - track_table[i*4+2] = len & 0xff; - track_table[i*4+3] = (len>>8) & 0xff; - } - // Set the remainder to 0xff - for (int i=m_cylinders*4; i < TRACK_TABLE_LENGTH; i++) - track_table[i] = 0xff; - - io.write_at(0x200, track_table, TRACK_TABLE_LENGTH, actual); - } - // Write the current cylinder - io.write_at(m_cyl_offset[cyl]<<9, &cylbuf[0], (m_cyl_length[cyl] + 0x1ff) & 0xfe00, actual); - } - return true; -} - -void hfe_format::generate_hfe_bitstream_from_track(int cyl, int head, int& samplelength, encoding_t& encoding, uint8_t *cylinder_buffer, int track_end, floppy_image *image) -{ - // We are using an own implementation here because the result of the - // parent class method would require some post-processing that we - // can easily avoid. - - // See floppy_image_format_t::generate_bitstream_from_track - // as the original code - - // No subtracks definded - std::vector &tbuf = image->get_buffer(cyl, head, 0); - if (tbuf.size() <= 1) - { - // Unformatted track - // TODO must handle that according to HFE - int track_size = 200000000/samplelength; - memset(cylinder_buffer, 0, (track_size+7)/8); - return; - } - - // Find out whether we have FM or MFM recording, and determine the bit rate. - // This is needed for the format header. - // - // The encoding may have changed by reformatting; we cannot rely on the - // header when loading. - // - // FM: encoding 1 -> flux length = 4 us (min) ambivalent - // encoding 10 -> flux length = 8 us (max) ambivalent - // MFM: encoding 10 -> flux length = 4 us (min, DD) ambivalent - // encoding 100 -> flux length = 6 us (DD) significant - // encoding 1000 -> flux length = 8 us (max, DD) ambivalent - // encoding 10 -> flux length = 2 us (min, HD) significant - // encoding 100 -> flux length = 3 us (max, HD) significant - - // If we have MFM, we should very soon detect a flux length of 6 us. - // But if we have FM, how long should we search to be sure? - // We assume that after 2000 us we should have reached the first IDAM, - // which contains a sequence 1001, implying a flux length of 6 us. - // If there was no such flux in that area, this can safely be assumed to be FM. - - // Do it only for the first track; the format only supports one encoding. - if (encoding == UNKNOWN_ENCODING) - { - bool mfm_recording = false; - int time0 = 0; - int minflux = 4000; - int fluxlen = 0; - // Skip the beginning (may have a short cell) - for (int i=2; (i < tbuf.size()-1) && (time0 < 2000000) && !mfm_recording; i++) - { - time0 = tbuf[i] & floppy_image::TIME_MASK; - fluxlen = (tbuf[i+1] & floppy_image::TIME_MASK) - time0; - if ((fluxlen < 3500) || (fluxlen > 5500 && fluxlen < 6500)) - mfm_recording = true; - if (fluxlen < minflux) minflux = fluxlen; - } - encoding = mfm_recording? ISOIBM_MFM_ENCODING : ISOIBM_FM_ENCODING; - - // samplelength = 1000ns => 10^6 cells/sec => 500 kbit/s - // samplelength = 2000ns => 250 kbit/s - // We stay with double sampling at 250 kbit/s for FM - if (minflux < 3500) samplelength = 1000; - else samplelength = 2000; - } - - // Start at the write splice - uint32_t splice = image->get_write_splice_position(cyl, head, 0); - - int cur_pos = splice; - int cur_entry = 0; - - // Fast-forward to the write splice position (always 0 in this format) - while (cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry+1] & floppy_image::TIME_MASK) < cur_pos) - cur_entry++; - - int period = samplelength; - int period_adjust_base = period * 0.05; - - int min_period = int(samplelength*0.75); - int max_period = int(samplelength*1.25); - int phase_adjust = 0; - int freq_hist = 0; - uint32_t next = 0; - - int offset = 0x100; - - // Prepare offset for the format storage - if (head==0) - { - offset = 0; - track_end -= 0x0100; - } - - uint8_t bit = 0x01; - uint8_t current = 0; - - while (next < 200000000) { - int edge = tbuf[cur_entry] & floppy_image::TIME_MASK; - - // Start of track? Use next entry. - if (edge==0) - { - edge = tbuf[++cur_entry] & floppy_image::TIME_MASK; - } - - // Wrapped over end? - if (edge < cur_pos) edge += 200000000; - - // End of cell - next = cur_pos + period + phase_adjust; - - // End of the window is at next; edge is the actual transition - if (edge >= next) - { - // No transition in the window -> 0 - phase_adjust = 0; - } - else - { - // Transition in the window -> 1 - current |= bit; - int delta = edge - (next - period/2); - - phase_adjust = 0.65*delta; - - if (delta < 0) - { - if (freq_hist < 0) freq_hist--; - else freq_hist = -1; - } - else - { - if (delta > 0) - { - if(freq_hist > 0) freq_hist++; - else freq_hist = 1; - } - else freq_hist = 0; - } - - if (freq_hist) - { - int afh = freq_hist < 0 ? -freq_hist : freq_hist; - if (afh > 1) - { - int aper = period_adjust_base*delta/period; - if (!aper) - aper = freq_hist < 0 ? -1 : 1; - period += aper; - - if (period < min_period) period = min_period; - else if (period > max_period) period = max_period; - } - } - } - - cur_pos = next; - - bit = (bit << 1) & 0xff; - if (bit == 0) - { - bit = 0x01; - cylinder_buffer[offset++] = current; - if ((offset & 0xff)==0) offset += 0x100; - current = 0; - } - - // Fast-forward to next cell - while (cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos) - cur_entry++; - - // Reaching the end of the track - if (cur_entry == int(tbuf.size())-1 && (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos) - { - // Wrap to index 0 or 1 depending on whether there is a transition exactly at the index hole - cur_entry = (tbuf[int(tbuf.size())-1] & floppy_image::MG_MASK) != (tbuf[0] & floppy_image::MG_MASK) ? - 0 : 1; - } - } - // Write the current byte when not done - if (bit != 0x01) - cylinder_buffer[offset] = current; -} - const floppy_format_type FLOPPY_HFE_FORMAT = &floppy_image_format_creator; diff --git a/src/lib/formats/hxchfe_dsk.h b/src/lib/formats/hxchfe_dsk.h index 4ea98ed861c..a332e2dc2fc 100644 --- a/src/lib/formats/hxchfe_dsk.h +++ b/src/lib/formats/hxchfe_dsk.h @@ -49,40 +49,40 @@ public: virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector &variants) override; virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector &variants, floppy_image *image) override; - virtual bool save(util::random_read_write &io, const std::vector &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; virtual bool supports_save() const override; - void set_floppy_mode(floppymode_t mode) { m_selected_mode = mode; } - void set_encoding(encoding_t enc) { m_selected_encoding = enc; } - private: void generate_track_from_hfe_bitstream(int track, int head, int samplelength, const uint8_t *trackbuf, int track_end, floppy_image *image); - void generate_hfe_bitstream_from_track(int track, int head, int& samplelength, encoding_t& encoding, uint8_t *trackbuf, int track_end, floppy_image *image); // Header fields from the HFE format - int m_cylinders; // Number of track in the file - int m_heads; // Number of valid side - encoding_t m_track_encoding; // Track Encoding mode - int m_bit_rate; // Bitrate in Kbit/s (max: 500) - int m_floppy_rpm; // Rotation per minute - floppymode_t m_interface_mode; // Floppy interface mode. + struct header_info { + int m_cylinders = 0; // Number of track in the file + int m_heads = 0; // Number of valid side + encoding_t m_track_encoding = UNKNOWN_ENCODING; // Track Encoding mode + int m_bit_rate = 0; // Bitrate in Kbit/s (max: 500) + int m_floppy_rpm = 0; // Rotation per minute + floppymode_t m_interface_mode = DISABLE_FLOPPYMODE; // Floppy interface mode. - bool m_write_allowed; - bool m_single_step; - bool m_track0s0_has_altencoding; - encoding_t m_track0s0_encoding; // alternate track_encoding for track 0 Side 0 - bool m_track0s1_has_altencoding; - encoding_t m_track0s1_encoding; // alternate track_encoding for track 0 Side 1 + bool m_write_allowed = true; + bool m_single_step = true; + bool m_track0s0_has_altencoding = false; + encoding_t m_track0s0_encoding = UNKNOWN_ENCODING; // alternate track_encoding for track 0 Side 0 + bool m_track0s1_has_altencoding = false; + encoding_t m_track0s1_encoding = UNKNOWN_ENCODING; // alternate track_encoding for track 0 Side 1 - int m_cyl_offset[256]; - int m_cyl_length[256]; + int m_cyl_offset[256]; + int m_cyl_length[256]; - floppymode_t m_selected_mode; - encoding_t m_selected_encoding; + floppymode_t m_selected_mode = DISABLE_FLOPPYMODE; + encoding_t m_selected_encoding = UNKNOWN_ENCODING; + }; + + void set_floppy_mode(header_info &info, floppymode_t mode) { info.m_selected_mode = mode; } + void set_encoding(header_info &info, encoding_t enc) { info.m_selected_encoding = enc; } }; extern const floppy_format_type FLOPPY_HFE_FORMAT;