From 5e34c1b6b8fa283d71e2b1687aaad02c0f29bf54 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 1 May 2018 20:31:42 -0400 Subject: [PATCH] Switches to producing a single segment for NIBs and DSKs. I've now seemingly verified that the values read back by the CPU are those I'm intending to produce, so I'm at a loss. --- Storage/Disk/DiskImage/Formats/AppleDSK.cpp | 18 ++++++------- Storage/Disk/DiskImage/Formats/NIB.cpp | 13 ++++----- Storage/Disk/Track/PCMSegment.cpp | 30 +++++++++++++++++++++ Storage/Disk/Track/PCMSegment.hpp | 2 ++ 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/Storage/Disk/DiskImage/Formats/AppleDSK.cpp b/Storage/Disk/DiskImage/Formats/AppleDSK.cpp index fe9521365..a3c86c2e7 100644 --- a/Storage/Disk/DiskImage/Formats/AppleDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/AppleDSK.cpp @@ -47,7 +47,7 @@ std::shared_ptr AppleDSK::get_track_at_position(Track::Address address) { file_.seek(file_offset, SEEK_SET); const std::vector track_data = file_.read(static_cast(bytes_per_sector * sectors_per_track_)); - std::vector segments; + Storage::Disk::PCMSegment segment; const uint8_t track = static_cast(address.position >> 2); // In either case below, the code aims for exactly 50,000 bits per track. @@ -55,11 +55,10 @@ std::shared_ptr AppleDSK::get_track_at_position(Track::Address address) { // Write the sectors. uint8_t sector_number_ = 0; for(std::size_t c = 0; c < 16; ++c) { - segments.push_back(Encodings::AppleGCR::six_and_two_sync(10)); - segments.push_back(Encodings::AppleGCR::header(0, track, sector_number_)); - segments.push_back(Encodings::AppleGCR::six_and_two_sync(10)); - segments.push_back(Encodings::AppleGCR::six_and_two_data(&track_data[c * 256])); - segments.push_back(Encodings::AppleGCR::six_and_two_sync(10)); + segment += Encodings::AppleGCR::six_and_two_sync(10); + segment += Encodings::AppleGCR::header(0, track, sector_number_); + segment += Encodings::AppleGCR::six_and_two_sync(10); + segment += Encodings::AppleGCR::six_and_two_data(&track_data[c * 256]); // DOS and Pro DOS interleave sectors on disk, and they're represented in a disk // image in physical order rather than logical. So that skew needs to be applied here. @@ -68,13 +67,12 @@ std::shared_ptr AppleDSK::get_track_at_position(Track::Address address) { } // Pad if necessary. - int encoded_length = (80 + 112 + 80 + 2848 + 80) * sectors_per_track_; - if(encoded_length < 50000) { - segments.push_back(Encodings::AppleGCR::six_and_two_sync((50000 - encoded_length) >> 3)); + if(segment.number_of_bits < 50000) { + segment += Encodings::AppleGCR::six_and_two_sync((50000 - segment.number_of_bits) >> 3); } } else { } - return std::shared_ptr(new PCMTrack(segments)); + return std::make_shared(segment); } diff --git a/Storage/Disk/DiskImage/Formats/NIB.cpp b/Storage/Disk/DiskImage/Formats/NIB.cpp index afc5870f3..656ac1b3e 100644 --- a/Storage/Disk/DiskImage/Formats/NIB.cpp +++ b/Storage/Disk/DiskImage/Formats/NIB.cpp @@ -50,7 +50,7 @@ std::shared_ptr<::Storage::Disk::Track> NIB::get_track_at_position(::Storage::Di // tracks and headers), then treat all following FFs as a sync // region, then switch back to ordinary behaviour as soon as a // non-FF appears. - std::vector segments; + PCMSegment segment; std::size_t start_index = 0; std::set sync_starts; @@ -74,8 +74,9 @@ std::shared_ptr<::Storage::Disk::Track> NIB::get_track_at_position(::Storage::Di } } - if(start_index) - segments.push_back(Encodings::AppleGCR::six_and_two_sync(static_cast(start_index))); + if(start_index) { + segment += Encodings::AppleGCR::six_and_two_sync(static_cast(start_index)); + } std::size_t index = start_index; for(const auto &location: sync_starts) { @@ -86,7 +87,7 @@ std::shared_ptr<::Storage::Disk::Track> NIB::get_track_at_position(::Storage::Di track_data.begin() + static_cast(index), track_data.begin() + static_cast(location)); data_segment.number_of_bits = static_cast(data_segment.data.size() * 8); - segments.push_back(std::move(data_segment)); + segment += data_segment; // Add a sync from sync_start to end of 0xffs. if(location == track_length-1) break; @@ -94,8 +95,8 @@ std::shared_ptr<::Storage::Disk::Track> NIB::get_track_at_position(::Storage::Di index = location; while(index < track_length && track_data[index] == 0xff) ++index; - segments.push_back(Encodings::AppleGCR::six_and_two_sync(static_cast(index - location))); + segment += Encodings::AppleGCR::six_and_two_sync(static_cast(index - location)); } - return std::shared_ptr(new PCMTrack(segments)); + return std::make_shared(segment); } diff --git a/Storage/Disk/Track/PCMSegment.cpp b/Storage/Disk/Track/PCMSegment.cpp index da07e0248..119084c47 100644 --- a/Storage/Disk/Track/PCMSegment.cpp +++ b/Storage/Disk/Track/PCMSegment.cpp @@ -43,6 +43,36 @@ void PCMSegmentEventSource::reset() { next_event_.type = Track::Event::FluxTransition; } +PCMSegment &PCMSegment::operator +=(const PCMSegment &rhs) { + if(!rhs.number_of_bits) return *this; + + if(number_of_bits&7) { + auto target_number_of_bits = number_of_bits + rhs.number_of_bits; + data.resize((target_number_of_bits + 7) >> 3); + + std::size_t first_byte = number_of_bits >> 3; + + int shift = number_of_bits&7; + data[first_byte] |= rhs.data[0] >> shift; + for(std::size_t target = first_byte+1; target < (data.size()-1); ++target) { + data[target] = + static_cast( + (rhs.data[target - first_byte - 1] << (8 - shift)) | + (rhs.data[target - first_byte] >> shift) + ); + } + data.back() = static_cast(rhs.data.back() << (8 - shift)); + + number_of_bits = target_number_of_bits; + } else { + data.insert(data.end(), rhs.data.begin(), rhs.data.end()); + number_of_bits += rhs.number_of_bits; + } + + return *this; +} + + 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 ea9bd4779..b7687a505 100644 --- a/Storage/Disk/Track/PCMSegment.hpp +++ b/Storage/Disk/Track/PCMSegment.hpp @@ -41,6 +41,8 @@ struct PCMSegment { number_of_bits = 0; data.clear(); } + + PCMSegment &operator +=(const PCMSegment &rhs); }; /*!