From 5b1757061251d14fc8cfd8817d17fcbf1d6dc3cc Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Tue, 19 Apr 2022 17:53:17 +0200 Subject: [PATCH] flopimg: Fix issues when wrapping in generate_bitstream_from_track which were especially damaging for apple drivers --- src/lib/formats/flopimg.cpp | 188 +++++++++++++++++++++++------------- 1 file changed, 119 insertions(+), 69 deletions(-) diff --git a/src/lib/formats/flopimg.cpp b/src/lib/formats/flopimg.cpp index c2cb7e18b2b..6d57e4f1b8d 100644 --- a/src/lib/formats/flopimg.cpp +++ b/src/lib/formats/flopimg.cpp @@ -1316,92 +1316,142 @@ std::vector floppy_image_format_t::generate_bitstream_from_track(int track return trackbuf; } - // Start at the write splice - uint32_t splice = image->get_write_splice_position(track, head, subtrack); - int cur_pos = splice; - int cur_entry = 0; - while(cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry+1] & floppy_image::TIME_MASK) < cur_pos) - cur_entry++; + class pll { + private: + const std::vector &tbuf; + int cur_pos; + int cur_entry; + int period; + int period_adjust_base; + int min_period; + int max_period; + int phase_adjust; + int freq_hist; + bool next_is_first; - int period = cell_size; - int period_adjust_base = period * 0.05; + public: + pll(const std::vector &_tbuf, int cell_size) : tbuf(_tbuf) { + period = cell_size; + period_adjust_base = period * 0.05; - int min_period = int(cell_size*0.75); - int max_period = int(cell_size*1.25); - int phase_adjust = 0; - int freq_hist = 0; + min_period = int(cell_size*0.75); + max_period = int(cell_size*1.25); + phase_adjust = 0; + freq_hist = 0; - uint32_t scanned = 0; - while(scanned < 200000000) { - // Note that only MG_F edges are taken into account, the rest is ignored. - // The lack of MG_F has been tested for previously. - while((tbuf[cur_entry] & floppy_image::MG_MASK) != floppy_image::MG_F) { - cur_entry ++; - if(cur_entry == tbuf.size()) - cur_entry = 0; + // Try to go back 16 flux changes from the end of the track, or at most at the start + int flux_to_step = 16; + cur_entry = tbuf.size()-1; + while(cur_entry > 0 && flux_to_step) { + if((tbuf[cur_entry] & floppy_image::MG_MASK) == floppy_image::MG_F) + flux_to_step --; + cur_entry--; + } + + // Go back by half-a-period + cur_pos = (tbuf[cur_entry] & floppy_image::TIME_MASK) - period/2; + + // Adjust the entry accordingly + while(cur_entry > 0 && (cur_pos > (tbuf[cur_entry] & floppy_image::TIME_MASK))) + cur_entry --; + + // Now go to the next flux change from there (the no-MG_F case has been handled earlier) + while((tbuf[cur_entry] & floppy_image::MG_MASK) != floppy_image::MG_F) + cur_entry ++; + + next_is_first = false; } - int edge = tbuf[cur_entry] & floppy_image::TIME_MASK; - if(edge < cur_pos) - edge += 200000000; - int next = cur_pos + period + phase_adjust; - scanned += period + phase_adjust; + std::pair get() { + bool bit, first; + int edge = tbuf[cur_entry] & floppy_image::TIME_MASK; + if(edge < cur_pos) + edge += 200000000; + int next = cur_pos + period + phase_adjust; - if(edge >= next) { - // No transition in the window means 0 and pll in free run mode - trackbuf.push_back(false); - phase_adjust = 0; + if(edge >= next) { + // No transition in the window means 0 and pll in free run mode + bit = false; + phase_adjust = 0; - } else { - // Transition in the window means 1, and the pll is adjusted - trackbuf.push_back(true); + } else { + // Transition in the window means 1, and the pll is adjusted + bit = true; - int delta = edge - (next - period/2); + int delta = edge - (next - period/2); - phase_adjust = 0.65*delta; + 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(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(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; + if(period < min_period) + period = min_period; + else if(period > max_period) + period = max_period; + } } } - } - cur_pos = next; - if(cur_pos >= 200000000) { - cur_pos -= 200000000; - cur_entry = 0; - } - while(cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos) - cur_entry++; + first = next_is_first; + next_is_first = false; - // Wrap around - if(cur_entry == int(tbuf.size())-1 && - (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos) - cur_entry = 0; + cur_pos = next; + if(cur_pos >= 200000000) { + cur_pos -= 200000000; + cur_entry = 0; + + if(cur_pos >= period/2) + first = true; + else + next_is_first = true; + } + while(cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos) + cur_entry++; + + // Wrap around + if(cur_entry == int(tbuf.size())-1 && + (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos) + cur_entry = 0; + + return std::make_pair(bit, first); + } + }; + + pll cpll(tbuf, cell_size); + + for(;;) { + auto r = cpll.get(); + if(r.second) { + trackbuf.push_back(r.first); + break; + } } + for(;;) { + auto r = cpll.get(); + if(r.second) + break; + trackbuf.push_back(r.first); + } + return trackbuf; }