summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2022-04-19 17:53:17 +0200
committer Olivier Galibert <galibert@pobox.com>2022-04-19 17:53:23 +0200
commit5b1757061251d14fc8cfd8817d17fcbf1d6dc3cc (patch)
tree0fdeeeedb32dc157a0a0c23ddffb1046b6be458e /src/lib/formats
parent6d3c4ff49a52a814ac3fa8f63ffad36406b5bab7 (diff)
flopimg: Fix issues when wrapping in generate_bitstream_from_track which were especially damaging for apple drivers
Diffstat (limited to 'src/lib/formats')
-rw-r--r--src/lib/formats/flopimg.cpp198
1 files changed, 124 insertions, 74 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<bool> 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++;
-
- int period = cell_size;
- int 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;
-
- 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;
- }
+ class pll {
+ private:
+ const std::vector<uint32_t> &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;
+
+ public:
+ pll(const std::vector<uint32_t> &_tbuf, int cell_size) : tbuf(_tbuf) {
+ period = cell_size;
+ period_adjust_base = period * 0.05;
+
+ min_period = int(cell_size*0.75);
+ max_period = int(cell_size*1.25);
+ phase_adjust = 0;
+ freq_hist = 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--;
+ }
- 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;
+ // Go back by half-a-period
+ cur_pos = (tbuf[cur_entry] & floppy_image::TIME_MASK) - period/2;
- if(edge >= next) {
- // No transition in the window means 0 and pll in free run mode
- trackbuf.push_back(false);
- phase_adjust = 0;
+ // Adjust the entry accordingly
+ while(cur_entry > 0 && (cur_pos > (tbuf[cur_entry] & floppy_image::TIME_MASK)))
+ cur_entry --;
- } else {
- // Transition in the window means 1, and the pll is adjusted
- trackbuf.push_back(true);
+ // 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 ++;
- int delta = edge - (next - period/2);
+ next_is_first = false;
+ }
- phase_adjust = 0.65*delta;
+ std::pair<bool, bool> 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
+ bit = false;
+ phase_adjust = 0;
+
+ } else {
+ // Transition in the window means 1, and the pll is adjusted
+ bit = true;
+
+ 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;
+ }
+ }
+ }
- if(delta < 0) {
- if(freq_hist < 0)
- freq_hist--;
- else
- freq_hist = -1;
- } else if(delta > 0) {
- if(freq_hist > 0)
- freq_hist++;
+ first = next_is_first;
+ next_is_first = false;
+
+ cur_pos = next;
+ if(cur_pos >= 200000000) {
+ cur_pos -= 200000000;
+ cur_entry = 0;
+
+ if(cur_pos >= period/2)
+ first = true;
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;
- }
+ 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;
- cur_pos = next;
- if(cur_pos >= 200000000) {
- cur_pos -= 200000000;
- cur_entry = 0;
+ return std::make_pair(bit, first);
}
- while(cur_entry < int(tbuf.size())-1 && (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos)
- cur_entry++;
+ };
+
+ pll cpll(tbuf, cell_size);
- // Wrap around
- if(cur_entry == int(tbuf.size())-1 &&
- (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos)
- cur_entry = 0;
+ 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;
}