diff options
author | 2022-03-30 14:28:37 +0200 | |
---|---|---|
committer | 2022-03-30 15:45:35 +0200 | |
commit | 08f28cee11ce94e6656d4924c7a3c30614811783 (patch) | |
tree | ec993e6409ededbc8dfc38c351b92dd1eab6e35f /src | |
parent | 40033c809aed228af9b928747a882ee275482c38 (diff) |
floppy: Change the internal format to flux changes, update the mfi format accordingly (keep read compatibility with the old mfi)
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/imagedev/floppy.cpp | 266 | ||||
-rw-r--r-- | src/devices/imagedev/floppy.h | 14 | ||||
-rw-r--r-- | src/lib/formats/ap2_dsk.cpp | 16 | ||||
-rw-r--r-- | src/lib/formats/dfi_dsk.cpp | 16 | ||||
-rw-r--r-- | src/lib/formats/flopimg.cpp | 148 | ||||
-rw-r--r-- | src/lib/formats/flopimg.h | 34 | ||||
-rw-r--r-- | src/lib/formats/hxchfe_dsk.cpp | 19 | ||||
-rw-r--r-- | src/lib/formats/mfi_dsk.cpp | 114 | ||||
-rw-r--r-- | src/lib/formats/mfi_dsk.h | 14 | ||||
-rw-r--r-- | src/lib/formats/vt_dsk.cpp | 94 | ||||
-rw-r--r-- | src/lib/formats/vt_dsk.h | 4 |
11 files changed, 338 insertions, 401 deletions
diff --git a/src/devices/imagedev/floppy.cpp b/src/devices/imagedev/floppy.cpp index 6ab5b934944..922fddfbbdc 100644 --- a/src/devices/imagedev/floppy.cpp +++ b/src/devices/imagedev/floppy.cpp @@ -1127,11 +1127,6 @@ uint32_t floppy_image_device::find_position(attotime &base, const attotime &when return res; } -bool floppy_image_device::test_track_last_entry_warps(const std::vector<uint32_t> &buf) const -{ - return !((buf[buf.size() - 1]^buf[0]) & floppy_image::MG_MASK); -} - attotime floppy_image_device::position_to_time(const attotime &base, int position) const { return base + attotime::from_double(position/angular_speed); @@ -1141,19 +1136,13 @@ void floppy_image_device::cache_fill_index(const std::vector<uint32_t> &buf, int { int cells = buf.size(); - if(index != 0 || !test_track_last_entry_warps(buf)) { - cache_index = index; - cache_start_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK); - } else { - cache_index = cells - 1; - cache_start_time = position_to_time(base - rev_time, buf[cache_index] & floppy_image::TIME_MASK); - } - + cache_index = index; + cache_start_time = position_to_time(base, buf[index] & floppy_image::TIME_MASK); cache_entry = buf[cache_index]; index ++; if(index >= cells) { - index = test_track_last_entry_warps(buf) ? 1 : 0; + index = 0; base += rev_time; } @@ -1268,161 +1257,146 @@ void floppy_image_device::write_flux(const attotime &start, const attotime &end, track_dirty = true; cache_clear(); + std::vector<wspan> wspans(1); + attotime base; - int start_pos = find_position(base, start); - int end_pos = find_position(base, end); + wspans[0].start = find_position(base, start); + wspans[0].end = find_position(base, end); - std::vector<int> trans_pos(transition_count); for(int i=0; i != transition_count; i++) - trans_pos[i] = find_position(base, transitions[i]); + wspans[0].flux_change_positions.push_back(find_position(base, transitions[i])); + + wspan_split_on_wrap(wspans); std::vector<uint32_t> &buf = image->get_buffer(cyl, ss, subcyl); - int index; - if(!buf.empty()) - index = find_index(start_pos, buf); - else { - index = 0; + if(buf.empty()) { buf.push_back(floppy_image::MG_N); + buf.push_back(floppy_image::MG_E | 199999999); } - uint32_t cur_mg; - if((buf[index] & floppy_image::TIME_MASK) == start_pos) { - if(index) - cur_mg = buf[index-1]; - else - cur_mg = buf[buf.size() - 1]; - } else - cur_mg = buf[index]; - - cur_mg &= floppy_image::MG_MASK; - if(cur_mg == floppy_image::MG_N || cur_mg == floppy_image::MG_D) - cur_mg = floppy_image::MG_A; - - uint32_t pos = start_pos; - int ti = 0; - int cells = buf.size(); - if(transition_count != 0 && trans_pos[0] == pos) { - cur_mg = cur_mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - ti ++; - } - while(pos != end_pos) { - if(buf.size() < cells+10) - buf.resize(cells+200); - uint32_t next_pos; - if(ti != transition_count) - next_pos = trans_pos[ti++]; - else - next_pos = end_pos; - if(next_pos > pos) - write_zone(&buf[0], cells, index, pos, next_pos, cur_mg); - else { - write_zone(&buf[0], cells, index, pos, 200000000, cur_mg); - index = 0; - write_zone(&buf[0], cells, index, 0, next_pos, cur_mg); - } - pos = next_pos; - cur_mg = cur_mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - } - - buf.resize(cells); -} + wspan_remove_damaged(wspans, buf); + wspan_write(wspans, buf); -void floppy_image_device::write_zone(uint32_t *buf, int &cells, int &index, uint32_t spos, uint32_t epos, uint32_t mg) -{ cache_clear(); - while(spos < epos) { - while(index != cells-1 && (buf[index+1] & floppy_image::TIME_MASK) <= spos) - index++; - - uint32_t ref_start = buf[index] & floppy_image::TIME_MASK; - uint32_t ref_end = index == cells-1 ? 200000000 : buf[index+1] & floppy_image::TIME_MASK; - uint32_t ref_mg = buf[index] & floppy_image::MG_MASK; +} - // Can't overwrite a damaged zone - if(ref_mg == floppy_image::MG_D) { - spos = ref_end; - continue; - } +void floppy_image_device::wspan_split_on_wrap(std::vector<wspan> &wspans) +{ + int ne = wspans.size(); + for(int i=0; i != ne; i++) + if(wspans[i].end < wspans[i].start) { + wspans.resize(wspans.size()+1); + auto &ws = wspans[i]; + auto &we = wspans.back(); + we.start = 0; + we.end = ws.end; + ws.end = 200000000; + int start = ws.start; + int split_index; + for(split_index = 0; split_index != ws.flux_change_positions.size(); split_index++) + if(ws.flux_change_positions[split_index] < start) + break; + if(split_index == 0) + std::swap(ws.flux_change_positions, we.flux_change_positions); - // If the zone is of the type we want, we don't need to touch it - if(ref_mg == mg) { - spos = ref_end; - continue; + else { + we.flux_change_positions.resize(ws.flux_change_positions.size() - split_index); + std::copy(ws.flux_change_positions.begin() + split_index, ws.flux_change_positions.end(), we.flux_change_positions.begin()); + ws.flux_change_positions.erase(ws.flux_change_positions.begin() + split_index, ws.flux_change_positions.end()); + } } +} - // Check the overlaps, act accordingly - if(spos == ref_start) { - if(epos >= ref_end) { - // Full overlap, that cell is dead, we need to see which ones we can extend - uint32_t prev_mg = index != 0 ? buf[index-1] & floppy_image::MG_MASK : ~0; - uint32_t next_mg = index != cells-1 ? buf[index+1] & floppy_image::MG_MASK : ~0; - if(prev_mg == mg) { - if(next_mg == mg) { - // Both match, merge all three in one - memmove(buf+index, buf+index+2, (cells-index-2)*sizeof(uint32_t)); - cells -= 2; - index--; - - } else { - // Previous matches, drop the current cell - memmove(buf+index, buf+index+1, (cells-index-1)*sizeof(uint32_t)); - cells --; - } - - } else { - if(next_mg == mg) { - // Following matches, extend it - memmove(buf+index, buf+index+1, (cells-index-1)*sizeof(uint32_t)); - cells --; - buf[index] = mg | spos; - } else { - // None match, convert the current cell - buf[index] = mg | spos; - index++; - } +void floppy_image_device::wspan_remove_damaged(std::vector<wspan> &wspans, const std::vector<uint32_t> &track) +{ + for(size_t pos = 0; pos != track.size(); pos++) + if((track[pos] & floppy_image::MG_MASK) == floppy_image::MG_D) { + int start = track[pos] & floppy_image::TIME_MASK; + int end = track[pos+1] & floppy_image::TIME_MASK; + int ne = wspans.size(); + for(int i=0; i != ne; i++) { + // D range outside of span range + if(wspans[i].start > end || wspans[i].end <= start) + continue; + + // D range covers span range + if(wspans[i].start >= start && wspans[i].end-1 <= end) { + wspans.erase(wspans.begin() + i); + i --; + ne --; + continue; } - spos = ref_end; - } else { - // Overlap at the start only - // Check if we can just extend the previous cell - if(index != 0 && (buf[index-1] & floppy_image::MG_MASK) == mg) - buf[index] = ref_mg | epos; - else { - // Otherwise we need to insert a new cell - if(index != cells-1) - memmove(buf+index+1, buf+index, (cells-index)*sizeof(uint32_t)); - cells++; - buf[index] = mg | spos; - buf[index+1] = ref_mg | epos; + // D range covers the start of the span range + if(wspans[i].start >= start && wspans[i].end-1 > end) { + wspans[i].start = end+1; + while(!wspans[i].flux_change_positions.empty() && wspans[i].flux_change_positions[0] <= end) + wspans[i].flux_change_positions.erase(wspans[i].flux_change_positions.begin()); + continue; } - spos = epos; - } - } else { - if(epos >= ref_end) { - // Overlap at the end only - // If we can't just extend the following cell, we need to insert a new one - if(index == cells-1 || (buf[index+1] & floppy_image::MG_MASK) != mg) { - if(index != cells-1) - memmove(buf+index+2, buf+index+1, (cells-index-1)*sizeof(uint32_t)); - cells++; + // D range covers the end of the span range + if(wspans[i].start < start && wspans[i].end-1 <= end) { + wspans[i].end = start; + while(!wspans[i].flux_change_positions.empty() && wspans[i].flux_change_positions[wspans[i].flux_change_positions.size()-1] >= start) + wspans[i].flux_change_positions.erase(wspans[i].flux_change_positions.end()-1); + continue; } - buf[index+1] = mg | spos; - index++; - spos = ref_end; + // D range is inside the span range, need to split + int id = wspans.size(); + wspans.resize(id+1); + wspans[id].start = end+1; + wspans[id].end = wspans[i].end; + wspans[id].flux_change_positions = wspans[i].flux_change_positions; + wspans[i].end = start; + while(!wspans[i].flux_change_positions.empty() && wspans[i].flux_change_positions[wspans[i].flux_change_positions.size()-1] >= start) + wspans[i].flux_change_positions.erase(wspans[i].flux_change_positions.end()-1); + while(!wspans[id].flux_change_positions.empty() && wspans[id].flux_change_positions[0] <= end) + wspans[id].flux_change_positions.erase(wspans[id].flux_change_positions.begin()); + } + } +} + +void floppy_image_device::wspan_write(const std::vector<wspan> &wspans, std::vector<uint32_t> &track) +{ + for(const auto &ws : wspans) { + unsigned si, ei; + for(si = 0; si != track.size(); si++) + if((track[si] & floppy_image::TIME_MASK) >= ws.start) + break; + for(ei = si; ei != track.size(); ei++) + if((track[ei] & floppy_image::TIME_MASK) >= ws.end) + break; + + // Reduce neutral zone at the start, if there's one + if(si != track.size() && (track[si] & floppy_image::MG_MASK) == floppy_image::MG_E) { + // Neutral zone is over the whole range, split it and adapt si/ei + if(si == ei) { + track.insert(track.begin() + si, floppy_image::MG_E | (ws.start-1)); + track.insert(track.begin() + si + 1, (track[si-1] & floppy_image::MG_MASK) | ws.end); + si = ei = si+1; } else { - // Full inclusion - // We need to split the zone in 3 - if(index != cells-1) - memmove(buf+index+3, buf+index+1, (cells-index-1)*sizeof(uint32_t)); - cells += 2; - buf[index+1] = mg | spos; - buf[index+2] = ref_mg | epos; - spos = epos; + // Reduce the zone size + track[si] = floppy_image::MG_E | (ws.start-1); + si ++; } + } + + // Check for a neutral zone at the end and reduce it if needed + if(ei != track.size() && (track[ei] & floppy_image::MG_MASK) == floppy_image::MG_E) { + track[ei-1] = floppy_image::MG_N | ws.end; + ei --; + } + + // Clear the covered zone + track.erase(track.begin() + si, track.begin() + ei); + + // Insert the flux changes + for(auto f : ws.flux_change_positions) { + track.insert(track.begin() + si, floppy_image::MG_F | f); + si ++; } } } diff --git a/src/devices/imagedev/floppy.h b/src/devices/imagedev/floppy.h index a91624c2a23..3f2030e839c 100644 --- a/src/devices/imagedev/floppy.h +++ b/src/devices/imagedev/floppy.h @@ -228,7 +228,6 @@ protected: attotime revolution_start_time, rev_time; uint32_t revolution_count; int cyl, subcyl; - /* Current floppy zone cache */ attotime cache_start_time, cache_end_time, cache_weak_start; attotime amplifier_freakout_time; @@ -246,15 +245,24 @@ protected: wpt_cb cur_wpt_cb; led_cb cur_led_cb; + + // Temporary structure storing a write span + struct wspan { + int start, end; + std::vector<int> flux_change_positions; + }; + + static void wspan_split_on_wrap(std::vector<wspan> &wspans); + static void wspan_remove_damaged(std::vector<wspan> &wspans, const std::vector<uint32_t> &track); + static void wspan_write(const std::vector<wspan> &wspans, std::vector<uint32_t> &track); + void register_formats(); void check_led(); uint32_t find_position(attotime &base, const attotime &when); int find_index(uint32_t position, const std::vector<uint32_t> &buf) const; - bool test_track_last_entry_warps(const std::vector<uint32_t> &buf) const; attotime position_to_time(const attotime &base, int position) const; - void write_zone(uint32_t *buf, int &cells, int &index, uint32_t spos, uint32_t epos, uint32_t mg); void commit_image(); u32 hash32(u32 val) const; diff --git a/src/lib/formats/ap2_dsk.cpp b/src/lib/formats/ap2_dsk.cpp index 880ab10d092..2b6d6c07c88 100644 --- a/src/lib/formats/ap2_dsk.cpp +++ b/src/lib/formats/ap2_dsk.cpp @@ -1674,7 +1674,21 @@ bool a2_woz_format::load(util::random_read &io, uint32_t form_factor, const std: if (r32(img, trks_off + 4) == 0) return false; - generate_track_from_bitstream(track, head, &img[boff], r32(img, trks_off + 4), image, subtrack, 0xffff); + uint32_t track_size = r32(img, trks_off + 4); + + // With 5.25 floppies the end-of-track may be missing + // if unformatted. Accept track length down to 95% of + // 51090, otherwise pad it + + bool short_track = !is_35 && track_size < 48535; + + if(short_track) { + std::vector<uint8_t> buffer(6387, 0); + memcpy(buffer.data(), &img[boff], (track_size + 7) / 8); + generate_track_from_bitstream(track, head, buffer.data(), 51090, image, subtrack, 0xffff); + + } else + generate_track_from_bitstream(track, head, &img[boff], track_size, image, subtrack, 0xffff); if(is_35 && !track && head) image->set_variant(r32(img, trks_off + 4) >= 90000 ? floppy_image::DSHD : floppy_image::DSDD); diff --git a/src/lib/formats/dfi_dsk.cpp b/src/lib/formats/dfi_dsk.cpp index c7afcb2cda0..ea6b23a43f9 100644 --- a/src/lib/formats/dfi_dsk.cpp +++ b/src/lib/formats/dfi_dsk.cpp @@ -177,9 +177,7 @@ bool dfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve #endif index_count = 0; //index_polarity = 0; - uint32_t mg = floppy_image::MG_A; int tpos = 0; - buf[tpos++] = mg; for(int i=0; i<tsize; i++) { uint8_t v = data[i]; if((v & 0x7f) == 0x7f) // 0x7F : no transition, but a carry (FF is a board-on-fire error and is checked for above) @@ -202,23 +200,19 @@ bool dfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve //if (trans_time <= MIN_THRESH) osd_printf_verbose("dfi_dsk: Throwing out short transition of length %d\n", trans_time); // the normal case: write the transition at the appropriate time if ((prev_time == 0) || ((trans_time > MIN_THRESH) && (trans_time <= MAX_THRESH))) { - mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - buf[tpos++] = mg | uint32_t((200000000ULL*cur_time)/index_time); + buf[tpos++] = floppy_image::MG_F | uint32_t((200000000ULL*cur_time)/index_time); prev_time = cur_time; } // the long case: we probably missed a transition, stuff an extra guessed one in there to see if it helps if (trans_time > MAX_THRESH) { - mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; if (((track%2)==0)&&(head==0)) osd_printf_info("dfi_dsk: missed transition, total time for transition is %d\n",trans_time); #ifndef FAKETRANS_ONE - buf[tpos++] = mg | uint32_t((200000000ULL*(cur_time-(trans_time/2)))/index_time); // generate imaginary transition at half period + buf[tpos++] = floppy_image::MG_F | uint32_t((200000000ULL*(cur_time-(trans_time/2)))/index_time); // generate imaginary transition at half period #else - buf[tpos++] = mg | uint32_t((200000000ULL*(cur_time-((trans_time*2)/3)))/index_time); - mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - buf[tpos++] = mg | uint32_t((200000000ULL*(cur_time-(trans_time/3)))/index_time); + buf[tpos++] = floppy_image::MG_F | uint32_t((200000000ULL*(cur_time-((trans_time*2)/3)))/index_time); + buf[tpos++] = floppy_image::MG_F | uint32_t((200000000ULL*(cur_time-(trans_time/3)))/index_time); #endif - mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - buf[tpos++] = mg | uint32_t(200000000ULL*cur_time/index_time); // generate transition now + buf[tpos++] = floppy_image::MG_F | uint32_t(200000000ULL*cur_time/index_time); // generate transition now prev_time = cur_time; } } diff --git a/src/lib/formats/flopimg.cpp b/src/lib/formats/flopimg.cpp index 413c69f4a22..c2cb7e18b2b 100644 --- a/src/lib/formats/flopimg.cpp +++ b/src/lib/formats/flopimg.cpp @@ -91,9 +91,10 @@ bool floppy_image::track_is_formatted(int track, int head, int subtrack) const auto &data = track_array[idx][head].cell_data; if(data.empty()) return false; - if(data.size() == 1 && (data[0] & MG_MASK) == MG_N) - return false; - return true; + for(uint32_t mg : data) + if((mg & floppy_image::MG_MASK) == floppy_image::MG_F) + return true; + return false; } const char *floppy_image::get_variant_name(uint32_t form_factor, uint32_t variant) @@ -840,17 +841,11 @@ void floppy_image_format_t::generate_track(const desc_e *desc, int track, int he generate_track_from_levels(track, head, buffer, 0, image); } -void floppy_image_format_t::normalize_times(std::vector<uint32_t> &buffer) +void floppy_image_format_t::normalize_times(std::vector<uint32_t> &buffer, uint32_t last_position) { - unsigned int total_sum = 0; - for(unsigned int i=0; i != buffer.size(); i++) - total_sum += buffer[i] & floppy_image::TIME_MASK; - - unsigned int current_sum = 0; for(unsigned int i=0; i != buffer.size(); i++) { uint32_t time = buffer[i] & floppy_image::TIME_MASK; - buffer[i] = (buffer[i] & floppy_image::MG_MASK) | (200000000ULL * current_sum / total_sum); - current_sum += time; + buffer[i] = (buffer[i] & floppy_image::MG_MASK) | (200000000ULL * time / last_position); } } @@ -859,36 +854,11 @@ void floppy_image_format_t::generate_track_from_bitstream(int track, int head, c std::vector<uint32_t> &dest = image->get_buffer(track, head, subtrack); dest.clear(); - // If the bitstream has an odd number of inversions, one needs to be added. - // Put in in the middle of the half window after the center inversion, where - // any fdc ignores it. - - int inversions = 0; for(int i=0; i != track_size; i++) if(trackbuf[i >> 3] & (0x80 >> (i & 7))) - inversions++; - bool need_flux = inversions & 1; + dest.push_back(floppy_image::MG_F | (i*2+1)); - uint32_t cbit = floppy_image::MG_A; - uint32_t count = 0; - for(int i=0; i != track_size; i++) - if(trackbuf[i >> 3] & (0x80 >> (i & 7))) { - dest.push_back(cbit | (count+2)); - cbit = cbit == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - if(need_flux) { - need_flux = false; - dest.push_back(cbit | 1); - cbit = cbit == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - count = 1; - } else - count = 2; - } else - count += 4; - - if(count) - dest.push_back(cbit | count); - - normalize_times(dest); + normalize_times(dest, track_size*2); if(splice >= 0 || splice < track_size) { int splpos = uint64_t(200000000) * splice / track_size; @@ -902,81 +872,23 @@ void floppy_image_format_t::generate_track_from_levels(int track, int head, std: splice_pos = splice_pos % trackbuf.size(); uint32_t splice_angular_pos = trackbuf[splice_pos] & floppy_image::TIME_MASK; - // Check if we need to invert a cell to get an even number of - // transitions on the whole track - // - // Also check if all MG values are valid - - int transition_count = 0; - for(auto & elem : trackbuf) { - switch(elem & floppy_image::MG_MASK) { - case MG_1: - transition_count++; - break; - - case MG_W: - throw std::runtime_error(util::string_format("Weak bits not yet handled, track %d head %d", track, head)); - - case MG_0: - case floppy_image::MG_N: - case floppy_image::MG_D: - break; - - case floppy_image::MG_A: - case floppy_image::MG_B: - default: - throw std::invalid_argument(util::string_format("Incorrect MG information in generate_track_from_levels, track %d head %d", track, head)); - } - } - - if(transition_count & 1) { - int pos = splice_pos; - while((trackbuf[pos] & floppy_image::MG_MASK) != MG_0 && (trackbuf[pos] & floppy_image::MG_MASK) != MG_1) { - pos++; - if(pos == int(trackbuf.size())) - pos = 0; - if(pos == splice_pos) - goto meh; - } - if((trackbuf[pos] & floppy_image::MG_MASK) == MG_0) - trackbuf[pos] = (trackbuf[pos] & floppy_image::TIME_MASK) | MG_1; - else - trackbuf[pos] = (trackbuf[pos] & floppy_image::TIME_MASK) | MG_0; - - meh: - ; - - } - - // Maximal number of cells which happens when the buffer is all MG_1/MG_N alternated, which would be 3/2 std::vector<uint32_t> &dest = image->get_buffer(track, head); dest.clear(); - uint32_t cbit = floppy_image::MG_A; - uint32_t count = 0; + uint32_t total_time = 0; for(auto & elem : trackbuf) { uint32_t bit = elem & floppy_image::MG_MASK; uint32_t time = elem & floppy_image::TIME_MASK; - if(bit == MG_0) { - count += time; - continue; - } - if(bit == MG_1) { - count += time >> 1; - dest.push_back(cbit | count); - cbit = cbit == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; - count = time - (time >> 1); - continue; - } - dest.push_back(cbit | count); - dest.push_back(elem); - count = 0; - } + if(bit == MG_1) + dest.push_back(floppy_image::MG_F | (total_time + (time >> 1))); + + else if(bit != MG_0) + dest.push_back(bit | total_time); - if(count) - dest.push_back(cbit | count); + total_time += time; + } - normalize_times(dest); + normalize_times(dest, total_time); image->set_write_splice_position(track, head, splice_angular_pos); } @@ -1390,7 +1302,14 @@ std::vector<bool> floppy_image_format_t::generate_bitstream_from_track(int track { std::vector<bool> trackbuf; std::vector<uint32_t> &tbuf = image->get_buffer(track, head, subtrack); - if(tbuf.size() <= 1) { + bool track_has_info = false; + for(uint32_t mg : tbuf) + if((mg & floppy_image::MG_MASK) == floppy_image::MG_F) { + track_has_info = true; + break; + } + + if(!track_has_info) { // Unformatted track int track_size = 200000000/cell_size; trackbuf.resize(track_size, false); @@ -1414,8 +1333,14 @@ std::vector<bool> floppy_image_format_t::generate_bitstream_from_track(int track uint32_t scanned = 0; while(scanned < 200000000) { - // Note that all magnetic cell type changes are considered - // edges. No randomness added for neutral/damaged cells + // 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; + } + int edge = tbuf[cur_entry] & floppy_image::TIME_MASK; if(edge < cur_pos) edge += 200000000; @@ -1474,11 +1399,8 @@ std::vector<bool> floppy_image_format_t::generate_bitstream_from_track(int track // Wrap around 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; - } + (tbuf[cur_entry] & floppy_image::TIME_MASK) < cur_pos) + cur_entry = 0; } return trackbuf; } diff --git a/src/lib/formats/flopimg.h b/src/lib/formats/flopimg.h index 2fd07c9f2a7..62daaaa2ac8 100644 --- a/src/lib/formats/flopimg.h +++ b/src/lib/formats/flopimg.h @@ -230,8 +230,9 @@ protected: */ static void generate_track_from_levels(int track, int head, std::vector<uint32_t> &trackbuf, int splice_pos, floppy_image *image); - //! Normalize the times in a cell buffer to sum up to 200000000 - static void normalize_times(std::vector<uint32_t> &buffer); + //! Normalize the times in a cell buffer to bring the + //! 0..last_position range up to 0..200000000 + static void normalize_times(std::vector<uint32_t> &buffer, uint32_t last_position); // Some conversion tables for gcr static const uint8_t gcr5fw_tb[0x10], gcr5bw_tb[0x20]; @@ -450,19 +451,22 @@ private: //! Internal format is close but not identical to the mfi format. //! //! + //! Track data consists of a series of 32-bits lsb-first values -//! representing magnetic cells. Bits 0-27 indicate the absolute -//! position of the start of the cell (not the size), and bits -//! 28-31 the type. Type can be: -//! - 0, MG_A -> Magnetic orientation A -//! - 1, MG_B -> Magnetic orientation B -//! - 2, MG_N -> Non-magnetized zone (neutral) -//! - 3, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing +//! representing the magnetic state. Bits 0-27 indicate the absolute +//! position of encoded event, and bits ! 28-31 the type. Type can be: +//! - 0, MG_F -> Flux orientation change +//! - 1, MG_N -> Start of a non-magnetized zone (neutral) +//! - 2, MG_D -> Start of a damaged zone, reads as neutral but cannot be changed by writing +//! - 3, MG_E -> End of one of the previous zones, *inclusive* //! //! The position is in angular units of 1/200,000,000th of a turn. -//! The last cell implicit end position is of course 200,000,000. +//! A N or D zone must not wrap at the 200,000,000 position, it has to +//! be split in two (the first finishing at 199,999,999, the second +//! starting at 0) //! -//! Unformatted tracks are encoded as zero-size. +//! Unformatted tracks are encoded as zero-size, and are strictly equivalent +//! to (MG_N, 0), (MG_E, 199,999,999) //! //! The "track splice" information indicates where to start writing //! if you try to rewrite a physical disk with the data. Some @@ -491,10 +495,10 @@ public: TIME_MASK = 0x0fffffff, MG_MASK = 0xf0000000, MG_SHIFT = 28, //!< Bitshift constant for magnetic orientation data - MG_A = (0 << MG_SHIFT), //!< - 0, MG_A -> Magnetic orientation A - MG_B = (1 << MG_SHIFT), //!< - 1, MG_B -> Magnetic orientation B - MG_N = (2 << MG_SHIFT), //!< - 2, MG_N -> Non-magnetized zone (neutral) - MG_D = (3 << MG_SHIFT) //!< - 3, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing + MG_F = (0 << MG_SHIFT), //!< - 0, MG_F -> Flux orientation change + MG_N = (1 << MG_SHIFT), //!< - 1, MG_N -> Non-magnetized zone (neutral) + MG_D = (2 << MG_SHIFT), //!< - 2, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing + MG_E = (3 << MG_SHIFT) //!< - 3, MG_E -> End of zone }; diff --git a/src/lib/formats/hxchfe_dsk.cpp b/src/lib/formats/hxchfe_dsk.cpp index ba9d877a537..9a8047816c7 100644 --- a/src/lib/formats/hxchfe_dsk.cpp +++ b/src/lib/formats/hxchfe_dsk.cpp @@ -316,17 +316,11 @@ void hfe_format::generate_track_from_hfe_bitstream(int cyl, int head, int sample // HFE does not define subtracks; set to 0 // MG_1 / MG_0 are (logical) levels that indicate transition / no change - // MG_A / MG_B are physical flux directions - // - // Cell: | AAAABBBB | = MG_1 = | BBBBAAAA | - // | AAAAAAAA | = MG_0 = | BBBBBBBB | + // MG_F is the position of a flux transition std::vector<uint32_t> &dest = image->get_buffer(cyl, head, 0); dest.clear(); - // Start with MG_A - uint32_t cbit = floppy_image::MG_A; - int offset = 0x100; if (head==0) @@ -338,10 +332,6 @@ void hfe_format::generate_track_from_hfe_bitstream(int cyl, int head, int sample uint8_t current = 0; int time = 0; - dest.push_back(cbit | time); - - cbit = floppy_image::MG_B; - // Oversampled FM images (250 kbit/s) start with a 0, where a 1 is // expected for 125 kbit/s. // In order to make an oversampled image look like a normally sampled one, @@ -384,13 +374,8 @@ void hfe_format::generate_track_from_hfe_bitstream(int cyl, int head, int sample { time += samplelength; if ((current & 1)!=0) - { // Append another transition to the vector - dest.push_back(cbit | time); - - // Toggle the cell level - cbit = (cbit == floppy_image::MG_A)? floppy_image::MG_B : floppy_image::MG_A; - } + dest.push_back(floppy_image::MG_F | time); // HFE uses little-endian bit order current >>= 1; diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp index 59310f2bb65..b3d75a2a60e 100644 --- a/src/lib/formats/mfi_dsk.cpp +++ b/src/lib/formats/mfi_dsk.cpp @@ -7,6 +7,7 @@ #include <zlib.h> #include <cstring> +#include <functional> /* @@ -31,31 +32,27 @@ simple "compress" function. Track data consists of a series of 32-bits lsb-first values - representing magnetic cells. Bits 0-27 indicate the sizes, and bits - 28-31 the types. Type can be: - - 0, MG_A -> Magnetic orientation A - - 1, MG_B -> Magnetic orientation B - - 2, MG_N -> Non-magnetized zone (neutral) - - 3, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing + representing magnetic cells. Bits 0-27 indicate the position, + delta-packed (e.g. difference with the previous position, starts at + 0), and bits 28-31 the types. Type can be: - Remember that the fdcs detect transitions, not absolute levels, so - the actual physical significance of the orientation A and B is - arbitrary. + - 0, MG_F -> Flux orientation change + - 1, MG_N -> Non-magnetized zone (neutral) + - 2, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing + - 3, MG_E -> End of zone Tracks data is aligned so that the index pulse is at the start, whether the disk is hard-sectored or not. - The size is the angular size in units of 1/200,000,000th of a turn. - Such a size, not coincidentally at all, is also the flyover time in - nanoseconds for a perfectly stable 300rpm drive. That makes the - standard cell size of a MFM 3.5" DD floppy at 2000 exactly for - instance (2us). Smallest expected cell size is 500 (ED density - drives). + The position is the angular position in units of 1/200,000,000th of + a turn. A size in such units, not coincidentally at all, is also + the flyover time in nanoseconds for a perfectly stable 300rpm drive. + That makes the standard cell size of a MFM 3.5" DD floppy at 2000 + exactly for instance (2us). Smallest expected cell size is 500 (ED + density drives). - The sum of all sizes must of course be 200,000,000. - - An unformatted track is equivalent to one big MG_N cell covering a - whole turn, but is encoded as zero-size. + An unformatted track is equivalent to a pair (MG_N, 0), (MG_E, + 199999999) but is encoded as zero-size. The "track splice" information indicates where to start writing if you try to rewrite a physical disk with the data. Some @@ -72,7 +69,8 @@ TODO: big-endian support */ -const char mfi_format::sign[16] = "MESSFLOPPYIMAGE"; // Includes the final \0 +const char mfi_format::sign_old[16] = "MESSFLOPPYIMAGE"; // Includes the final \0 +const char mfi_format::sign[16] = "MAMEFLOPPYIMAGE"; // Includes the final \0 mfi_format::mfi_format() : floppy_image_format_t() { @@ -85,7 +83,7 @@ const char *mfi_format::name() const const char *mfi_format::description() const { - return "MESS floppy image"; + return "MAME floppy image"; } const char *mfi_format::extensions() const @@ -104,7 +102,7 @@ int mfi_format::identify(util::random_read &io, uint32_t form_factor, const std: size_t actual; io.read_at(0, &h, sizeof(header), actual); - if(memcmp( h.sign, sign, 16 ) == 0 && + if((memcmp( h.sign, sign, 16) == 0 || memcmp( h.sign, sign_old, 16) == 0) && (h.cyl_count & CYLINDER_MASK) <= 84 && (h.cyl_count >> RESOLUTION_SHIFT) < 3 && h.head_count <= 2 && @@ -129,7 +127,46 @@ bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve if(!h.cyl_count) return true; + std::function<void (const std::vector<uint32_t> &src, std::vector<uint32_t> &track)> converter; + + if(!memcmp( h.sign, sign, 16)) { + converter = [](const std::vector<uint32_t> &src, std::vector<uint32_t> &track) -> void { + uint32_t ctime = 0; + for(uint32_t mg : src) { + ctime += mg & TIME_MASK; + track.push_back((mg & MG_MASK) | ctime); + } + }; + + } else { + converter = [](const std::vector<uint32_t> &src, std::vector<uint32_t> &track) -> void { + unsigned int cell_count = src.size(); + uint32_t mg = src[0] & MG_MASK; + uint32_t wmg = src[cell_count - 1] & MG_MASK; + if(mg != wmg && (mg == OLD_MG_A || mg == OLD_MG_B) && (wmg == OLD_MG_A && wmg == OLD_MG_B)) + // Flux change at 0, add it + track.push_back(MG_F | 0); + + uint32_t ctime = 0; + for(unsigned int i=0; i != cell_count; i++) { + uint32_t nmg = src[i] & MG_MASK; + if(nmg == OLD_MG_N || nmg == OLD_MG_D) { + track.push_back((nmg == OLD_MG_N ? MG_N : MG_D) | ctime); + ctime += src[i] & TIME_MASK; + track.push_back(MG_E | (ctime-1)); + nmg = 0xffffffff; + } else { + if(mg != 0xffffffff && mg != nmg) + track.push_back(MG_F | ctime); + ctime += src[i] & TIME_MASK; + } + mg = nmg; + } + }; + } + std::vector<uint8_t> compressed; + std::vector<uint32_t> uncompressed; entry *ent = entries; for(unsigned int cyl=0; cyl <= (h.cyl_count - 1) << 2; cyl += 4 >> resolution) @@ -143,31 +180,22 @@ bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve continue; } + unsigned int cell_count = ent->uncompressed_size/4; compressed.resize(ent->compressed_size); + uncompressed.resize(cell_count); io.read_at(ent->offset, &compressed[0], ent->compressed_size, actual); - unsigned int cell_count = ent->uncompressed_size/4; - std::vector<uint32_t> &trackbuf = image->get_buffer(cyl >> 2, head, cyl & 3);; - trackbuf.resize(cell_count); - uLongf size = ent->uncompressed_size; - if(uncompress((Bytef *)&trackbuf[0], &size, &compressed[0], ent->compressed_size) != Z_OK) { + if(uncompress((Bytef *)uncompressed.data(), &size, &compressed[0], ent->compressed_size) != Z_OK) { fprintf(stderr, "fail1\n"); return false; } - uint32_t cur_time = 0; - for(unsigned int i=0; i != cell_count; i++) { - uint32_t next_cur_time = cur_time + (trackbuf[i] & TIME_MASK); - trackbuf[i] = (trackbuf[i] & MG_MASK) | cur_time; - cur_time = next_cur_time; - } - if(cur_time != 200000000) { - fprintf(stderr, "fail2 %d\n", cur_time); - return false; - } + std::vector<uint32_t> &trackbuf = image->get_buffer(cyl >> 2, head, cyl & 3);; + trackbuf.clear(); + converter(uncompressed, trackbuf); ent++; } @@ -214,13 +242,11 @@ bool mfi_format::save(util::random_read_write &io, const std::vector<uint32_t> & continue; } - memcpy(&precomp[0], &buffer[0], tsize*4); - for(int j=0; j<tsize-1; j++) - precomp[j] = (precomp[j] & floppy_image::MG_MASK) | - ((precomp[j+1] & floppy_image::TIME_MASK) - - (precomp[j] & floppy_image::TIME_MASK)); - precomp[tsize-1] = (precomp[tsize-1] & floppy_image::MG_MASK) | - (200000000 - (precomp[tsize-1] & floppy_image::TIME_MASK)); + uint32_t ctime = 0; + for(int i=0; i != tsize; i++) { + precomp[i] = (buffer[i] & MG_MASK) | ((buffer[i] & TIME_MASK) - ctime); + ctime = buffer[i] & TIME_MASK; + } uLongf csize = max_track_size*4 + 1000; if(compress(postcomp.get(), &csize, (const Bytef *)precomp.get(), tsize*4) != Z_OK) diff --git a/src/lib/formats/mfi_dsk.h b/src/lib/formats/mfi_dsk.h index b1c3e783044..93a95c81657 100644 --- a/src/lib/formats/mfi_dsk.h +++ b/src/lib/formats/mfi_dsk.h @@ -27,15 +27,21 @@ private: MG_MASK = 0xf0000000, MG_SHIFT = 28, - MG_A = (0 << MG_SHIFT), - MG_B = (1 << MG_SHIFT), - MG_N = (2 << MG_SHIFT), - MG_D = (3 << MG_SHIFT), + OLD_MG_A = (0 << MG_SHIFT), + OLD_MG_B = (1 << MG_SHIFT), + OLD_MG_N = (2 << MG_SHIFT), + OLD_MG_D = (3 << MG_SHIFT), + + MG_F = (0 << MG_SHIFT), //!< - 0, MG_F -> Flux orientation change + MG_N = (1 << MG_SHIFT), //!< - 1, MG_N -> Non-magnetized zone (neutral) + MG_D = (2 << MG_SHIFT), //!< - 2, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing + MG_E = (3 << MG_SHIFT), //!< - 3, MG_E -> End of zone RESOLUTION_SHIFT = 30, CYLINDER_MASK = 0x3fffffff }; + static const char sign_old[16]; static const char sign[16]; struct header { diff --git a/src/lib/formats/vt_dsk.cpp b/src/lib/formats/vt_dsk.cpp index c01906e7df3..957efab67ba 100644 --- a/src/lib/formats/vt_dsk.cpp +++ b/src/lib/formats/vt_dsk.cpp @@ -17,23 +17,20 @@ // One = | 2237 | 6950 | // 0.5us ~= 143 -void vtech_common_format::wbit(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, bool bit) +void vtech_common_format::wbit(std::vector<uint32_t> &buffer, uint32_t &pos, bool bit) { - buffer.push_back(pos | mg); - mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; if(bit) { pos += 2237; - buffer.push_back(pos | mg); - mg = mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; + buffer.push_back(pos | floppy_image::MG_F); pos += 6950; } else pos += 9187; } -void vtech_common_format::wbyte(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, uint8_t byte) +void vtech_common_format::wbyte(std::vector<uint32_t> &buffer, uint32_t &pos, uint8_t byte) { for(int i = 7; i >= 0; i--) - wbit(buffer, pos, mg, (byte >> i) & 1); + wbit(buffer, pos, (byte >> i) & 1); } void vtech_common_format::image_to_flux(const std::vector<uint8_t> &bdata, floppy_image *image) @@ -44,40 +41,39 @@ void vtech_common_format::image_to_flux(const std::vector<uint8_t> &bdata, flopp for(int track = 0; track != 40; track ++) { uint32_t pos = 0; - uint32_t mg = floppy_image::MG_A; std::vector<uint32_t> &buffer = image->get_buffer(track, 0); buffer.clear(); image->set_write_splice_position(track, 0, 0); // One window of pad at the start to avoid problems with the write splice - wbit(buffer, pos, mg, 0); + wbit(buffer, pos, 0); for(int sector = 0; sector != 16; sector ++) { uint8_t sid = sector_map[sector]; for(int i=0; i != 7; i++) - wbyte(buffer, pos, mg, 0x80); - wbyte(buffer, pos, mg, 0x00); - wbyte(buffer, pos, mg, 0xfe); - wbyte(buffer, pos, mg, 0xe7); - wbyte(buffer, pos, mg, 0x18); - wbyte(buffer, pos, mg, 0xc3); - wbyte(buffer, pos, mg, track); - wbyte(buffer, pos, mg, sid); - wbyte(buffer, pos, mg, track+sid); + wbyte(buffer, pos, 0x80); + wbyte(buffer, pos, 0x00); + wbyte(buffer, pos, 0xfe); + wbyte(buffer, pos, 0xe7); + wbyte(buffer, pos, 0x18); + wbyte(buffer, pos, 0xc3); + wbyte(buffer, pos, track); + wbyte(buffer, pos, sid); + wbyte(buffer, pos, track+sid); for(int i=0; i != 5; i++) - wbyte(buffer, pos, mg, 0x80); - wbyte(buffer, pos, mg, 0x00); - wbyte(buffer, pos, mg, 0xc3); - wbyte(buffer, pos, mg, 0x18); - wbyte(buffer, pos, mg, 0xe7); - wbyte(buffer, pos, mg, 0xfe); + wbyte(buffer, pos, 0x80); + wbyte(buffer, pos, 0x00); + wbyte(buffer, pos, 0xc3); + wbyte(buffer, pos, 0x18); + wbyte(buffer, pos, 0xe7); + wbyte(buffer, pos, 0xfe); uint16_t chk = 0; const uint8_t *src = bdata.data() + 16*128*track + 128*sid; for(int i=0; i != 128; i++) { chk += src[i]; - wbyte(buffer, pos, mg, src[i]); + wbyte(buffer, pos, src[i]); } - wbyte(buffer, pos, mg, chk); - wbyte(buffer, pos, mg, chk >> 8); + wbyte(buffer, pos, chk); + wbyte(buffer, pos, chk >> 8); } // Rest is just not formatted buffer.push_back(pos | floppy_image::MG_N); @@ -95,29 +91,37 @@ std::vector<uint8_t> vtech_common_format::flux_to_image(floppy_image *image) continue; std::vector<bool> bitstream; - int lpos = -1; - bool looped = !((buffer[sz-1] ^ buffer[0]) & floppy_image::MG_MASK); - int cpos = looped ? sz-1 : 0; - while(cpos != lpos) { - int dt = looped && cpos == sz-1 ? (200000000 - (buffer[cpos] & floppy_image::TIME_MASK)) + (buffer[1] & floppy_image::TIME_MASK) : - cpos == sz-1 ? 200000000 - (buffer[cpos] & floppy_image::TIME_MASK) : - (buffer[cpos+1] & floppy_image::TIME_MASK) - (buffer[cpos] & floppy_image::TIME_MASK); - int t = dt >= 9187 - 143 ? 0 : - dt >= 2237 - 143 && dt <= 2237 + 143 ? 1 : - 2; - if(t <= 1) { - if(lpos == -1) - lpos = cpos; - bitstream.push_back(t); + int cpos = 0; + while((buffer[cpos] & floppy_image::MG_MASK) != floppy_image::MG_F) { + cpos++; + if(cpos == sz) { + cpos = -1; + break; } - cpos += 1; - if(cpos == sz) - cpos = looped ? 1 : 0; + } + if(cpos == -1) + continue; + for(;;) { + int npos = cpos; + for(;;) { + npos ++; + if(npos == sz) + npos = 0; + if((buffer[npos] & floppy_image::MG_MASK) == floppy_image::MG_F) + break; + } + int dt = (buffer[npos] & floppy_image::TIME_MASK) - (buffer[cpos] & floppy_image::TIME_MASK); + if(dt < 0) + cpos += 200000000; + bitstream.push_back(dt < 9187 - 143); + if(npos <= cpos) + break; + cpos = npos; } int mode = 0; - looped = false; int pos = 0; int count = 0; + bool looped = false; uint8_t *dest = nullptr; [[maybe_unused]] uint16_t checksum = 0; uint64_t buf = 0; diff --git a/src/lib/formats/vt_dsk.h b/src/lib/formats/vt_dsk.h index dacdb19d90d..5711ae07cdb 100644 --- a/src/lib/formats/vt_dsk.h +++ b/src/lib/formats/vt_dsk.h @@ -22,8 +22,8 @@ protected: static void image_to_flux(const std::vector<uint8_t> &bdata, floppy_image *image); static std::vector<uint8_t> flux_to_image(floppy_image *image); - static void wbit(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, bool bit); - static void wbyte(std::vector<uint32_t> &buffer, uint32_t &pos, uint32_t &mg, uint8_t byte); + static void wbit(std::vector<uint32_t> &buffer, uint32_t &pos, bool bit); + static void wbyte(std::vector<uint32_t> &buffer, uint32_t &pos, uint8_t byte); }; class vtech_bin_format : public vtech_common_format { |