1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 16:31:42 +00:00

Makes an initial removal of PCMPatchedTrack. Farewell, old friend.

This commit is contained in:
Thomas Harte 2018-07-01 22:49:57 -04:00
parent b4be2cd063
commit abca38a548
13 changed files with 53 additions and 533 deletions

View File

@ -165,7 +165,7 @@ class HalfCycles: public WrappedInt<HalfCycles> {
constexpr HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
/// @returns The number of whole cycles completely covered by this span of half cycles.
constexpr Cycles cycles() {
constexpr Cycles cycles() const {
return Cycles(length_ >> 1);
}

View File

@ -43,7 +43,6 @@
4B055AA81FAE85EF0060FFFF /* Shifter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136871F78725F008B8ED9 /* Shifter.cpp */; };
4B055AA91FAE85EF0060FFFF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; };
4B055AAA1FAE85F50060FFFF /* CPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */; };
4B055AAB1FAE85FD0060FFFF /* PCMPatchedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */; };
4B055AAC1FAE85FD0060FFFF /* PCMSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518731F75E91800926311 /* PCMSegment.cpp */; };
4B055AAD1FAE85FD0060FFFF /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
4B055AAE1FAE85FD0060FFFF /* TrackSerialiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBFFEE51F7B27F1005F3FEB /* TrackSerialiser.cpp */; };
@ -125,7 +124,6 @@
4B0E61071FF34737002A9DBD /* MSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E61051FF34737002A9DBD /* MSX.cpp */; };
4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
4B0F94FF208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */; };
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */; };
4B12C0ED1FCFA98D005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
@ -186,7 +184,6 @@
4B44EBF51DC987AF00A7820C /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */; };
4B44EBF71DC9883B00A7820C /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */; };
4B44EBF91DC9898E00A7820C /* BCDTEST_beeb in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */; };
4B4518811F75E91A00926311 /* PCMPatchedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */; };
4B4518821F75E91A00926311 /* PCMSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518731F75E91800926311 /* PCMSegment.cpp */; };
4B4518831F75E91A00926311 /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
4B4518841F75E91A00926311 /* UnformattedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518771F75E91800926311 /* UnformattedTrack.cpp */; };
@ -720,7 +717,6 @@
4B0F94FC208C1A1600FE41D9 /* NIB.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NIB.cpp; sourceTree = "<group>"; };
4B0F94FD208C1A1600FE41D9 /* NIB.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = NIB.hpp; sourceTree = "<group>"; };
4B0F9500208C42A300FE41D9 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Target.hpp; path = AppleII/Target.hpp; sourceTree = "<group>"; };
4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMPatchedTrackTests.mm; sourceTree = "<group>"; };
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMSegmentEventSourceTests.mm; sourceTree = "<group>"; };
4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Keyboard.cpp; path = MSX/Keyboard.cpp; sourceTree = "<group>"; };
4B12C0EC1FCFA98D005BFD93 /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Keyboard.hpp; path = MSX/Keyboard.hpp; sourceTree = "<group>"; };
@ -827,8 +823,6 @@
4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = AllSuiteA.bin; path = AllSuiteA/AllSuiteA.bin; sourceTree = "<group>"; };
4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = 6502_functional_test.bin; path = "Klaus Dormann/6502_functional_test.bin"; sourceTree = "<group>"; };
4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */ = {isa = PBXFileReference; lastKnownFileType = file; name = BCDTEST_beeb; path = BCDTest/BCDTEST_beeb; sourceTree = "<group>"; };
4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMPatchedTrack.cpp; sourceTree = "<group>"; };
4B4518721F75E91800926311 /* PCMPatchedTrack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMPatchedTrack.hpp; sourceTree = "<group>"; };
4B4518731F75E91800926311 /* PCMSegment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMSegment.cpp; sourceTree = "<group>"; };
4B4518741F75E91800926311 /* PCMSegment.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMSegment.hpp; sourceTree = "<group>"; };
4B4518751F75E91800926311 /* PCMTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMTrack.cpp; sourceTree = "<group>"; };
@ -1849,12 +1843,10 @@
4B4518701F75E91800926311 /* Track */ = {
isa = PBXGroup;
children = (
4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */,
4B4518731F75E91800926311 /* PCMSegment.cpp */,
4B4518751F75E91800926311 /* PCMTrack.cpp */,
4BBFFEE51F7B27F1005F3FEB /* TrackSerialiser.cpp */,
4B4518771F75E91800926311 /* UnformattedTrack.cpp */,
4B4518721F75E91800926311 /* PCMPatchedTrack.hpp */,
4B4518741F75E91800926311 /* PCMSegment.hpp */,
4B4518761F75E91800926311 /* PCMTrack.hpp */,
4B4518881F75ECB100926311 /* Track.hpp */,
@ -2789,7 +2781,6 @@
4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */,
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */,
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */,
4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */,
4B2AF8681E513FC20027EE29 /* TIATests.mm */,
@ -3639,7 +3630,6 @@
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */,
4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */,
4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */,
4B055AAB1FAE85FD0060FFFF /* PCMPatchedTrack.cpp in Sources */,
4B055AC71FAE9AEE0060FFFF /* TIA.cpp in Sources */,
4B055AD21FAE9B0B0060FFFF /* Keyboard.cpp in Sources */,
4B89451B201967B4007DE474 /* ConfidenceSummary.cpp in Sources */,
@ -3812,7 +3802,6 @@
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.mm in Sources */,
4B894532201967B4007DE474 /* 6502.cpp in Sources */,
4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */,
4B4518811F75E91A00926311 /* PCMPatchedTrack.cpp in Sources */,
4BBB70A8202014E2002FE009 /* MultiCRTMachine.cpp in Sources */,
4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */,
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */,
@ -3964,7 +3953,6 @@
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */,
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */,
4B322E011F5A2990004EB04C /* Z80AllRAM.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -71,6 +71,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableAddressSanitizer = "YES"
enableASanStackUseAfterReturn = "YES"
disableMainThreadChecker = "YES"
launchStyle = "0"

View File

@ -1,195 +0,0 @@
//
// PCMPatchedTrackTests.m
// Clock Signal
//
// Created by Thomas Harte on 17/12/2016.
// Copyright 2016 Thomas Harte. All rights reserved.
//
#import <XCTest/XCTest.h>
#include "PCMTrack.hpp"
#include "PCMPatchedTrack.hpp"
@interface PCMPatchedTrackTests : XCTestCase
@end
@implementation PCMPatchedTrackTests
#pragma mark - Prebuilt tracks
- (std::shared_ptr<Storage::Disk::Track>)togglingTrack {
Storage::Disk::PCMSegment segment;
segment.data = { 0xff, 0xff, 0xff, 0xff };
segment.number_of_bits = 32;
return std::shared_ptr<Storage::Disk::Track>(new Storage::Disk::PCMTrack(segment));
}
- (std::shared_ptr<Storage::Disk::Track>)patchableTogglingTrack {
std::shared_ptr<Storage::Disk::Track> track = self.togglingTrack;
return std::shared_ptr<Storage::Disk::Track>(new Storage::Disk::PCMPatchedTrack(track));
}
- (std::shared_ptr<Storage::Disk::Track>)fourSegmentPatchedTrack {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
Storage::Disk::PCMPatchedTrack *patchable = static_cast<Storage::Disk::PCMPatchedTrack *>(patchableTrack.get());
for(int c = 0; c < 4; c++) {
Storage::Disk::PCMSegment segment;
segment.data = {0xff};
segment.number_of_bits = 8;
segment.length_of_a_bit.length = 1;
segment.length_of_a_bit.clock_rate = 32;
patchable->add_segment(Storage::Time(c, 4), segment, false);
}
return patchableTrack;
}
#pragma mark -
- (std::vector<Storage::Disk::Track::Event>)eventsFromTrack:(std::shared_ptr<Storage::Disk::Track>)track {
std::vector<Storage::Disk::Track::Event> events;
while(1) {
events.push_back(track->get_next_event());
if(events.back().type == Storage::Disk::Track::Event::IndexHole) break;
}
return events;
}
- (Storage::Time)timeForEvents:(const std::vector<Storage::Disk::Track::Event> &)events {
Storage::Time result(0);
for(const auto &event : events) {
result += event.length;
}
return result;
}
- (void)patchTrack:(std::shared_ptr<Storage::Disk::Track>)track withSegment:(Storage::Disk::PCMSegment)segment atTime:(Storage::Time)time {
Storage::Disk::PCMPatchedTrack *patchable = static_cast<Storage::Disk::PCMPatchedTrack *>(track.get());
patchable->add_segment(time, segment, false);
}
#pragma mark - Repeating Asserts
- (void)assertOneThirtyTwosForTrack:(std::shared_ptr<Storage::Disk::Track>)track {
// Confirm that there are now flux transitions (just the first five will do)
// located 1/32nd of a rotation apart.
for(int c = 0; c < 5; c++) {
Storage::Disk::Track::Event event = track->get_next_event();
XCTAssert(
event.length == (c ? Storage::Time(1, 32) : Storage::Time(1, 64)),
@"flux transitions should be 1/32nd of a track apart");
}
}
- (void)assertEvents:(const std::vector<Storage::Disk::Track::Event> &)events hasEntries:(size_t)numberOfEntries withEntry:(size_t)entry ofLength:(Storage::Time)time {
XCTAssert(events.size() == numberOfEntries, @"Should be %zu total events", numberOfEntries);
XCTAssert(events[entry].length == time, @"Event %zu should have been %d/%d long, was %d/%d", entry, time.length, time.clock_rate, events[entry].length.length, events[entry].length.clock_rate);
Storage::Time eventTime = [self timeForEvents:events];
XCTAssert(eventTime == Storage::Time(1), @"Total track length should be 1; was %d/%d", eventTime.length, eventTime.clock_rate);
}
#pragma mark - Unpatched tracks
- (void)testUnpatchedRawTrack {
[self assertOneThirtyTwosForTrack:self.togglingTrack];
}
- (void)testUnpatchedTrack {
[self assertOneThirtyTwosForTrack:self.patchableTogglingTrack];
}
#pragma mark - Insertions affecting one existing segment
- (void)testSingleSplice {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 32), 1, {0xff}) atTime:Storage::Time(3, 128)];
std::vector<Storage::Disk::Track::Event> events = [self eventsFromTrack:patchableTrack];
Storage::Time total_length = [self timeForEvents:events];
XCTAssert(events.size() == 33, @"Should still be 33 total events");
XCTAssert(events[0].length == Storage::Time(1, 64), @"First event should be after 1/64 as usual");
XCTAssert(events[1].length == Storage::Time(3, 128), @"Second event should be 3/128 later"); // ... as it was inserted at 3/128 and runs at the same rate as the main data, so first inserted event is at 3/128+1/64-1/64
XCTAssert(events[2].length == Storage::Time(5, 128), @"Should still be 33 total events"); // 1/64 = 2/128 to exit the patch, plus 3/128 to get to the next event, having spliced in 1/128 ahead of the normal clock
XCTAssert(total_length == Storage::Time(1), @"Total track length should still be 1");
}
- (void)testLeftReplace {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(0)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:0 ofLength:Storage::Time(33, 64)];
}
- (void)testRightReplace {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(1, 2)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:16 ofLength:Storage::Time(33, 64)];
}
#pragma mark - Insertions affecting three existing segments
- (void)testMultiSegmentTrack {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:33 withEntry:4 ofLength:Storage::Time(1, 32)];
}
- (void)testMultiTrimBothSideReplace {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(1, 8)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:4 ofLength:Storage::Time(17, 32)];
}
- (void)testMultiTrimRightReplace {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 8)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:4 ofLength:Storage::Time(13, 32)];
}
- (void)testMultiTrimLeftReplace {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 4)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:8 ofLength:Storage::Time(13, 32)];
}
#pragma mark - Insertions affecting two existing segments
- (void)testTwoSegmentOverlap {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 32), 8, {0x00}) atTime:Storage::Time(1, 8)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:25 withEntry:4 ofLength:Storage::Time(9, 32)];
}
- (void)testTwoSegmentRightReplace {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 8)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:4 ofLength:Storage::Time(13, 32)];
}
- (void)testTwoSegmentLeftReplace {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(0)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:0 ofLength:Storage::Time(25, 64)];
}
#pragma mark - Wrapping segment
- (void)testWrappingSegment {
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(5, 2), 1, {0x00}) atTime:Storage::Time(0)];
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:1 withEntry:0 ofLength:Storage::Time(1, 1)];
}
@end

View File

@ -17,11 +17,8 @@
- (Storage::Disk::PCMSegmentEventSource)segmentSource
{
Storage::Disk::PCMSegment alternatingFFs;
alternatingFFs.data = {0xff, 0x00, 0xff, 0x00};
alternatingFFs.length_of_a_bit.length = 1;
alternatingFFs.length_of_a_bit.clock_rate = 10;
alternatingFFs.number_of_bits = 32;
std::vector<uint8_t> data = {0xff, 0x00, 0xff, 0x00};
Storage::Disk::PCMSegment alternatingFFs(Storage::Time(1, 10), data.size()*8, data);
return Storage::Disk::PCMSegmentEventSource(alternatingFFs);
}

View File

@ -19,13 +19,11 @@
{
Storage::Disk::PCMSegment quickSegment, slowSegment;
quickSegment.data = {0xff};
quickSegment.number_of_bits = 8;
quickSegment.data = {true, true, true, true, true, true, true, true};
quickSegment.length_of_a_bit.length = 1;
quickSegment.length_of_a_bit.clock_rate = 100;
slowSegment.data = {0xff};
slowSegment.number_of_bits = 8;
slowSegment.data = {true, true, true, true, true, true, true, true};
slowSegment.length_of_a_bit.length = 1;
slowSegment.length_of_a_bit.clock_rate = 3;
@ -55,19 +53,16 @@
std::vector<Storage::Disk::PCMSegment> segments;
Storage::Disk::PCMSegment sync_segment;
sync_segment.data.resize(10);
sync_segment.number_of_bits = 10*8;
memset(sync_segment.data.data(), 0xff, sync_segment.data.size());
sync_segment.data.resize(10*8);
std::fill(sync_segment.data.begin(), sync_segment.data.end(), true);
Storage::Disk::PCMSegment header_segment;
header_segment.data.resize(14);
header_segment.number_of_bits = 14*8;
memset(header_segment.data.data(), 0xff, header_segment.data.size());
header_segment.data.resize(14*8);
std::fill(header_segment.data.begin(), header_segment.data.end(), true);
Storage::Disk::PCMSegment data_segment;
data_segment.data.resize(349);
data_segment.number_of_bits = 349*8;
memset(data_segment.data.data(), 0xff, data_segment.data.size());
data_segment.data.resize(349*8);
std::fill(data_segment.data.begin(), data_segment.data.end(), true);
for(std::size_t c = 0; c < 16; ++c) {
segments.push_back(sync_segment);

View File

@ -12,7 +12,6 @@
#include "../Drive.hpp"
#include "../DPLL/DigitalPhaseLockedLoop.hpp"
#include "../Track/PCMSegment.hpp"
#include "../Track/PCMPatchedTrack.hpp"
#include "../../../ClockReceiver/ClockReceiver.hpp"
#include "../../../ClockReceiver/ClockingHintSource.hpp"

View File

@ -310,14 +310,17 @@ void Drive::write_bit(bool value) {
}
void Drive::end_writing() {
static const size_t high_resolution_track_rate = 500000;
if(!is_reading_) {
is_reading_ = true;
if(!patched_track_) {
// Avoid creating a new patched track if this one is already patched
patched_track_ = std::dynamic_pointer_cast<PCMPatchedTrack>(track_);
if(!patched_track_) {
patched_track_.reset(new PCMPatchedTrack(track_));
patched_track_ = std::dynamic_pointer_cast<PCMTrack>(track_);
if(!patched_track_ || !patched_track_->is_resampled_clone()) {
Track *tr = track_.get();
patched_track_.reset(PCMTrack::resampled_clone(tr, high_resolution_track_rate));
}
}
patched_track_->add_segment(write_start_time_, write_segment_, clamp_writing_to_index_hole_);

View File

@ -11,7 +11,7 @@
#include "Disk.hpp"
#include "Track/PCMSegment.hpp"
#include "Track/PCMPatchedTrack.hpp"
#include "Track/PCMTrack.hpp"
#include "../TimedEventLoop.hpp"
#include "../../Activity/Observer.hpp"
@ -168,8 +168,8 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
bool clamp_writing_to_index_hole_ = false;
// If writing is occurring then the drive will be accumulating a write segment,
// for addition to a patched track.
std::shared_ptr<PCMPatchedTrack> patched_track_;
// for addition to a (high-resolution) PCM track.
std::shared_ptr<PCMTrack> patched_track_;
PCMSegment write_segment_;
Time write_start_time_;

View File

@ -1,222 +0,0 @@
//
// PCMPatchedTrack.cpp
// Clock Signal
//
// Created by Thomas Harte on 15/12/2016.
// Copyright 2016 Thomas Harte. All rights reserved.
//
#include "PCMPatchedTrack.hpp"
#include <cassert>
using namespace Storage::Disk;
PCMPatchedTrack::PCMPatchedTrack(std::shared_ptr<Track> underlying_track) :
underlying_track_(underlying_track) {
const Time zero(0);
const Time one(1);
periods_.emplace_back(zero, one, zero, nullptr);
active_period_ = periods_.begin();
underlying_track_->seek_to(zero);
}
PCMPatchedTrack::PCMPatchedTrack(const PCMPatchedTrack &original) {
underlying_track_.reset(original.underlying_track_->clone());
periods_ = original.periods_;
active_period_ = periods_.begin();
}
Track *PCMPatchedTrack::clone() const {
return new PCMPatchedTrack(*this);
}
void PCMPatchedTrack::add_segment(const Time &start_time, const PCMSegment &segment, bool clamp_to_index_hole) {
std::shared_ptr<PCMSegmentEventSource> event_source(new PCMSegmentEventSource(segment));
Time zero(0);
Time one(1);
Time end_time = start_time + event_source->get_length();
if(clamp_to_index_hole && end_time > one) {
end_time = one;
}
Period insertion_period(start_time, end_time, zero, event_source);
// the new segment may wrap around, so divide it up into track-length parts if required
assert(insertion_period.start_time <= one);
while(insertion_period.end_time > one) {
Time next_end_time = insertion_period.end_time - one;
insertion_period.end_time = one;
insert_period(insertion_period);
insertion_period.segment_start_time += one;
insertion_period.start_time = zero;
insertion_period.end_time = next_end_time;
}
insert_period(insertion_period);
// the vector may have been resized, potentially invalidating active_period_ even if
// the thing it pointed to is still the same thing. So work it out afresh.
insertion_error_ = current_time_ - seek_to(current_time_);
}
void PCMPatchedTrack::insert_period(const Period &period) {
// find the existing period that the new period starts in
std::vector<Period>::iterator start_period = periods_.begin();
while(start_period->end_time <= period.start_time) start_period++;
// find the existing period that the new period end in
std::vector<Period>::iterator end_period = start_period;
while(end_period->end_time < period.end_time) end_period++;
// perform a division if called for
if(start_period == end_period) {
if(start_period->start_time == period.start_time) {
if(start_period->end_time == period.end_time) {
// period has the same start and end time as start_period. So just replace it.
*start_period = period;
} else {
// period has the same start time as start_period but a different end time.
// So trim the left-hand side of start_period and insert the new period in front.
start_period->push_start_to_time(period.end_time);
periods_.insert(start_period, period);
}
} else {
if(start_period->end_time == period.end_time) {
// period has the same end time as start_period but a different start time.
// So trim the right-hand side of start_period and insert the new period afterwards
start_period->trim_end_to_time(period.start_time);
periods_.insert(start_period + 1, period);
} else {
// start_period has an earlier start and a later end than period. So copy it,
// trim the right off the original and the left off the copy, then insert the
// new period and the copy after start_period
Period right_period = *start_period;
right_period.push_start_to_time(period.end_time);
start_period->trim_end_to_time(period.start_time);
// the iterator isn't guaranteed to survive the insert, e.g. if it causes a resize
std::vector<Period>::difference_type offset = start_period - periods_.begin();
periods_.insert(start_period + 1, period);
periods_.insert(periods_.begin() + offset + 2, right_period);
}
}
} else {
bool should_insert = false;
std::vector<Period>::difference_type insertion_offset = 0;
if(start_period->start_time == period.start_time) {
// start_period starts at the same place as period. Period then
// ends after start_period. So replace.
*start_period = period;
should_insert = false;
} else {
// start_period starts before period. So trim and plan to insert afterwards.
start_period->trim_end_to_time(period.start_time);
should_insert = true;
insertion_offset = start_period + 1 - periods_.begin();
}
if(end_period->end_time == period.end_time) {
// end_period ends exactly when period does. So include it from the list to delete
end_period++;
} else {
end_period->push_start_to_time(period.end_time);
}
// remove everything that is exiting in between
periods_.erase(start_period + 1, end_period);
// insert the new period if required
if(should_insert)
periods_.insert(periods_.begin()+insertion_offset, period);
}
}
Track::Event PCMPatchedTrack::get_next_event() {
const Time one(1);
const Time zero(0);
Time extra_time(0);
Time period_error(0);
while(1) {
// get the next event from the current active period
Track::Event event;
if(active_period_->event_source) event = active_period_->event_source->get_next_event();
else event = underlying_track_->get_next_event();
// see what time that gets us to. If it's still within the current period, return the found event
Time event_time = current_time_ + event.length - period_error - insertion_error_;
if(event_time < active_period_->end_time) {
current_time_ = event_time;
// TODO: this is spelt out in three steps because times don't necessarily do the sensible
// thing when 'negative' if intermediate result get simplified in the meantime. So fix Time.
event.length += extra_time;
event.length -= period_error;
event.length -= insertion_error_;
return event;
}
insertion_error_.set_zero();
// otherwise move time back to the end of the outgoing period, accumulating the error into
// extra_time, and advance the extra period
extra_time += (active_period_->end_time - current_time_);
current_time_ = active_period_->end_time;
active_period_++;
// test for having reached the end of the track
if(active_period_ == periods_.end()) {
// if this is the end of the track then jump the active pointer back to the beginning
// of the list of periods and reset current_time_ to zero
active_period_ = periods_.begin();
if(active_period_->event_source) active_period_->event_source->reset();
else underlying_track_->seek_to(zero);
current_time_ = zero;
// then return an index hole that is the aggregation of accumulated extra_time away
event.type = Storage::Disk::Track::Event::IndexHole;
event.length = extra_time;
return event;
} else {
// if this is not the end of the track then move to the next period and note how much will need
// to be subtracted if an event is found here
if(active_period_->event_source) period_error = active_period_->segment_start_time - active_period_->event_source->seek_to(active_period_->segment_start_time);
else period_error = current_time_ - underlying_track_->seek_to(current_time_);
}
}
}
Storage::Time PCMPatchedTrack::seek_to(const Time &time_since_index_hole) {
// start at the beginning and continue while segments end before reaching the time sought
active_period_ = periods_.begin();
while(active_period_->end_time < time_since_index_hole) {
assert(active_period_ != periods_.end());
active_period_++;
}
// allow whatever storage represents the period found to perform its seek; calculation for periods
// with an event source is, in effect: seek_to(offset_into_segment + distance_into_period) - offset_into_segment.
if(active_period_->event_source)
current_time_ = active_period_->event_source->seek_to(active_period_->segment_start_time + time_since_index_hole - active_period_->start_time) + active_period_->start_time - active_period_->segment_start_time;
else
current_time_ = underlying_track_->seek_to(time_since_index_hole);
// The assert below is disabled as it assumes too much about total precision.
// assert(current_time_ <= time_since_index_hole);
return current_time_;
}
PCMPatchedTrack::Period::Period(const Period &original) :
start_time(original.start_time), end_time(original.end_time), segment_start_time(original.segment_start_time) {
if(original.event_source) event_source.reset(new PCMSegmentEventSource(*original.event_source));
}
void PCMPatchedTrack::Period::push_start_to_time(const Storage::Time &new_start_time) {
segment_start_time += new_start_time - start_time;
start_time = new_start_time;
}
void PCMPatchedTrack::Period::trim_end_to_time(const Storage::Time &new_end_time) {
end_time = new_end_time;
}

View File

@ -1,75 +0,0 @@
//
// PCMPatchedTrack.hpp
// Clock Signal
//
// Created by Thomas Harte on 15/12/2016.
// Copyright 2016 Thomas Harte. All rights reserved.
//
#ifndef PCMPatchedTrack_hpp
#define PCMPatchedTrack_hpp
#include "Track.hpp"
#include "PCMSegment.hpp"
namespace Storage {
namespace Disk {
/*!
A subclass of @c Track that patches an existing track with PCM segments.
*/
class PCMPatchedTrack: public Track {
public:
/*!
Constructs a @c PCMPatchedTrack that will return events from @c underlying_track in
regions where it has not had alternative PCM data installed.
*/
PCMPatchedTrack(std::shared_ptr<Track> underlying_track);
/*!
Copy constructor, for Track.
*/
PCMPatchedTrack(const PCMPatchedTrack &);
/*!
Replaces whatever is currently on the track from @c start_position to @c start_position + segment length
with the contents of @c segment.
@param start_time The time at which this segment begins. Must be in the range [0, 1).
@param segment The PCM segment to add.
@param clamp_to_index_hole If @c true then the new segment will be truncated if it overruns the index hole;
it will otherwise write over the index hole and continue.
*/
void add_segment(const Time &start_time, const PCMSegment &segment, bool clamp_to_index_hole);
// To satisfy Storage::Disk::Track
Event get_next_event() override;
Time seek_to(const Time &time_since_index_hole) override;
Track *clone() const override;
private:
std::shared_ptr<Track> underlying_track_;
struct Period {
Time start_time, end_time;
Time segment_start_time;
std::shared_ptr<PCMSegmentEventSource> event_source; // nullptr => use the underlying track
void push_start_to_time(const Storage::Time &new_start_time);
void trim_end_to_time(const Storage::Time &new_end_time);
Period(const Time &start_time, const Time &end_time, const Time &segment_start_time, std::shared_ptr<PCMSegmentEventSource> event_source) :
start_time(start_time), end_time(end_time), segment_start_time(segment_start_time), event_source(event_source) {}
Period(const Period &);
};
std::vector<Period> periods_;
std::vector<Period>::iterator active_period_;
Time current_time_, insertion_error_;
void insert_period(const Period &period);
};
}
}
#endif /* PCMPatchedTrack_hpp */

View File

@ -8,6 +8,7 @@
#include "PCMTrack.hpp"
#include "../../../NumberTheory/Factors.hpp"
#include "../../../Outputs/Log.hpp"
using namespace Storage::Disk;
@ -54,11 +55,25 @@ PCMTrack::PCMTrack(unsigned int bits_per_track) : PCMTrack() {
segment_event_sources_.emplace_back(segment);
}
PCMTrack *PCMTrack::resampled_clone(Track *original, size_t bits_per_track) {
PCMTrack *pcm_original = dynamic_cast<PCMTrack *>(original);
if(pcm_original) {
return pcm_original->resampled_clone(bits_per_track);
}
ERROR("NOT IMPLEMENTED: resampling non-PCMTracks");
return nullptr;
}
bool PCMTrack::is_resampled_clone() {
return is_resampled_clone_;
}
Track *PCMTrack::clone() const {
return new PCMTrack(*this);
}
Track *PCMTrack::resampled_clone(size_t bits_per_track) {
PCMTrack *PCMTrack::resampled_clone(size_t bits_per_track) {
// Create an empty track.
PCMTrack *const new_track = new PCMTrack(static_cast<unsigned int>(bits_per_track));
@ -70,6 +85,7 @@ Track *PCMTrack::resampled_clone(size_t bits_per_track) {
start_time += source.length();
}
new_track->is_resampled_clone_ = true;
return new_track;
}
@ -140,12 +156,18 @@ void PCMTrack::add_segment(const Time &start_time, const PCMSegment &segment, bo
const Time end_time = start_time + segment.length();
const size_t start_bit = start_time.length * destination.data.size() / start_time.clock_rate;
const size_t end_bit = end_time.length * destination.data.size() / end_time.clock_rate;
const size_t target_width = end_bit - start_bit;
// If clamping is applied, just put a hard cut-off at the index hole.
// if(clamp_to_index_hole) {
// end_bit = std::min(end_bit, destination.data.size());
// }
// !!TODO!! Deal with wrapping and clamping.
// Reset the destination.
std::fill(destination.data.begin() + static_cast<off_t>(start_bit), destination.data.begin() + static_cast<off_t>(end_bit), false);
// Step through the source data, and for each true map to a location in the destination and set it.
const size_t target_width = end_bit - start_bit;
const size_t half_offset = target_width / (2 * segment.data.size());
for(size_t bit = 0; bit < segment.data.size(); ++bit) {
if(segment.data[bit]) {

View File

@ -43,6 +43,11 @@ class PCMTrack: public Track {
*/
PCMTrack(const PCMTrack &);
/*!
Creates a PCMTrack by sampling the original at a rate of @c bits_per_track.
*/
static PCMTrack *resampled_clone(Track *original, size_t bits_per_track);
// as per @c Track
Event get_next_event() override;
Time seek_to(const Time &time_since_index_hole) override;
@ -50,7 +55,8 @@ class PCMTrack: public Track {
// Obtains a copy of this track, flattened to a single PCMSegment, which
// consists of @c bits_per_track potential flux transition points.
Track *resampled_clone(size_t bits_per_track);
PCMTrack *resampled_clone(size_t bits_per_track);
bool is_resampled_clone();
/*!
Replaces whatever is currently on the track from @c start_position to @c start_position + segment length
@ -80,6 +86,7 @@ class PCMTrack: public Track {
std::size_t segment_pointer_;
PCMTrack();
bool is_resampled_clone_ = false;
};
}