From 71ec7624ca3436f446643349235915879e54eb11 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 27 Aug 2018 20:56:25 -0400 Subject: [PATCH] Corrects Apple DSK track length, inter-track skew, and Pro-DOS volume number. --- Storage/Disk/DiskImage/Formats/AppleDSK.cpp | 11 ++++++++--- Storage/Disk/Track/PCMSegment.cpp | 19 +++++++++++++++++++ Storage/Disk/Track/PCMSegment.hpp | 7 +++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Storage/Disk/DiskImage/Formats/AppleDSK.cpp b/Storage/Disk/DiskImage/Formats/AppleDSK.cpp index f0780f9ff..3c155b699 100644 --- a/Storage/Disk/DiskImage/Formats/AppleDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/AppleDSK.cpp @@ -75,19 +75,24 @@ std::shared_ptr AppleDSK::get_track_at_position(Track::Address address) { // In either case below, the code aims for exactly 50,000 bits per track. if(sectors_per_track_ == 16) { // Write gap 1. - segment += Encodings::AppleGCR::six_and_two_sync(16); + segment += Encodings::AppleGCR::six_and_two_sync(24); // Write the sectors. for(uint8_t c = 0; c < 16; ++c) { - segment += Encodings::AppleGCR::header(254, track, c); + segment += Encodings::AppleGCR::header(is_prodos_ ? 0x01 : 0xfe, track, c); // Volume number is 0xfe for DOS 3.3, 0x01 for Pro-DOS. segment += Encodings::AppleGCR::six_and_two_sync(7); // Gap 2: 7 sync words. segment += Encodings::AppleGCR::six_and_two_data(&track_data[logical_sector_for_physical_sector(c) * 256]); - segment += Encodings::AppleGCR::six_and_two_sync(16); // Gap 3: 16 sync words. + segment += Encodings::AppleGCR::six_and_two_sync(20); // Gap 3: 20 sync words. } } else { // TODO: 5 and 3, 13-sector format. If DSK actually supports it? } + // Apply inter-track skew; skew is about 40ms between each track; assuming 300RPM that's + // 1/5th of a revolution. + const size_t offset_in_fifths = address.position.as_int() % 5; + segment.rotate_right(offset_in_fifths * segment.data.size() / 5); + return std::make_shared(segment); } diff --git a/Storage/Disk/Track/PCMSegment.cpp b/Storage/Disk/Track/PCMSegment.cpp index d70265780..554882103 100644 --- a/Storage/Disk/Track/PCMSegment.cpp +++ b/Storage/Disk/Track/PCMSegment.cpp @@ -50,6 +50,25 @@ PCMSegment &PCMSegment::operator +=(const PCMSegment &rhs) { return *this; } +void PCMSegment::rotate_right(size_t length) { + length %= data.size(); + if(!length) return; + + // To rotate to the right, front-insert the proper number + // of bits from the end and then resize. To rotate to + // the left, do the opposite. + std::vector data_copy; + if(length > 0) { + data_copy.insert(data_copy.end(), data.end() - static_cast(length), data.end()); + data.erase(data.end() - static_cast(length), data.end()); + data.insert(data.begin(), data_copy.begin(), data_copy.end()); + } else { + data_copy.insert(data_copy.end(), data.begin(), data.begin() - static_cast(length)); + data.erase(data.begin(), data.begin() - static_cast(length)); + data.insert(data.end(), data_copy.begin(), data_copy.end()); + } +} + Storage::Disk::Track::Event PCMSegmentEventSource::get_next_event() { // track the initial bit pointer for potentially considering whether this was an // initial index hole or a subsequent one later on diff --git a/Storage/Disk/Track/PCMSegment.hpp b/Storage/Disk/Track/PCMSegment.hpp index 3e206c0a2..b2a6fb75c 100644 --- a/Storage/Disk/Track/PCMSegment.hpp +++ b/Storage/Disk/Track/PCMSegment.hpp @@ -105,6 +105,13 @@ struct PCMSegment { data.clear(); } + /*! + Rotates all bits in this segment by @c length bits. + + @c length is signed; to rotate left provide a negative number. + */ + void rotate_right(size_t length); + /*! Produces a byte buffer where the contents of @c data are serialised into bytes