From f789ee4ff035f3b36e16d3782c52fa5747c6280b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 23 Sep 2017 22:39:19 -0400 Subject: [PATCH] Introduces a track to segment decoder. This will be needed to make formats like G64 and HFE writeable, but probably also will be usable to speed up static analysis. --- .../Clock Signal.xcodeproj/project.pbxproj | 2 + Storage/Disk/Track/TrackSerialiser.hpp | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 Storage/Disk/Track/TrackSerialiser.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 98d5ffd92..3e6372eab 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -680,6 +680,7 @@ 4B8805FA1DCFF807003085B1 /* Oric.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Oric.hpp; path = Parsers/Oric.hpp; sourceTree = ""; }; 4B8805FC1DD02552003085B1 /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tape.cpp; path = ../../StaticAnalyser/Oric/Tape.cpp; sourceTree = ""; }; 4B8805FD1DD02552003085B1 /* Tape.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Tape.hpp; path = ../../StaticAnalyser/Oric/Tape.hpp; sourceTree = ""; }; + 4B8D287E1F77207100645199 /* TrackSerialiser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TrackSerialiser.hpp; sourceTree = ""; }; 4B8E4ECD1DCE483D003716C3 /* KeyboardMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = KeyboardMachine.hpp; sourceTree = ""; }; 4B8FE2141DA19D5F0090D3CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Atari2600Options.xib"; sourceTree = SOURCE_ROOT; }; 4B8FE2161DA19D5F0090D3CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/MachineDocument.xib"; sourceTree = SOURCE_ROOT; }; @@ -1415,6 +1416,7 @@ 4B4518771F75E91800926311 /* UnformattedTrack.cpp */, 4B4518781F75E91800926311 /* UnformattedTrack.hpp */, 4B4518881F75ECB100926311 /* Track.hpp */, + 4B8D287E1F77207100645199 /* TrackSerialiser.hpp */, ); path = Track; sourceTree = ""; diff --git a/Storage/Disk/Track/TrackSerialiser.hpp b/Storage/Disk/Track/TrackSerialiser.hpp new file mode 100644 index 000000000..dcbc3b8a9 --- /dev/null +++ b/Storage/Disk/Track/TrackSerialiser.hpp @@ -0,0 +1,71 @@ +// +// TrackSerialiser.hpp +// Clock Signal +// +// Created by Thomas Harte on 23/09/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef TrackSerialiser_h +#define TrackSerialiser_h + +#include "../DPLL/DigitalPhaseLockedLoop.hpp" + +namespace Storage { +namespace Disk { + +/*! + Instantiates a PLL with a target bit length of @c length_of_a_bit and provides a complete + serialisation of @c track, starting from the index hole. + + This feature is offered for the benefit of various parts of the code that need to make + sense of a track **other than emulation**, as it renders a one-off image of the track, + which can be inaccurate. However there are many occasions where a single rendering is + desireable — e.g. file formats that apply that constraint, or static analysis prior to + emulation launch, which works with broad strokes. + + @param track The track to serialise. + @param length_of_a_bit The expected length of a single bit, as a proportion of the + track length. +*/ +template PCMSegment track_serialisation(T &track, Time length_of_a_bit) { + DigitalPhaseLockedLoop pll(100, 16); + + struct ResultAccumulator: public DigitalPhaseLockedLoop::Delegate { + PCMSegment result; + void digital_phase_locked_loop_output_bit(int value) { + result.data.resize(1 + (result.number_of_bits >> 3)); + if(value) result.data[result.number_of_bits >> 3] |= 0x80 >> (result.number_of_bits & 7); + result.number_of_bits++; + } + } result_accumulator; + pll.set_delegate(&result_accumulator); + result_accumulator.result.number_of_bits = 0; + result_accumulator.result.length_of_a_bit = length_of_a_bit; + + Time length_multiplier = Time(100*length_of_a_bit.clock_rate, length_of_a_bit.length); + length_multiplier.simplify(); + + // start at the index hole + track.seek_to(Time(0)); + + // grab events until the next index hole + Time time_error = Time(0); + while(true) { + Track::Event next_event = track.get_next_event(); + if(next_event.type == Track::Event::IndexHole) break; + + Time extended_length = next_event.length * length_multiplier + time_error; + time_error.clock_rate = extended_length.clock_rate; + time_error.length = extended_length.length % extended_length.clock_rate; + pll.run_for(Cycles((int)extended_length.get_unsigned_int())); + pll.add_pulse(); + } + + return result_accumulator.result; +} + +} +} + +#endif /* TrackSerialiser_h */