From 9e3d6b762b4dd6da3c3bcb9f999bc116ff260879 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 10 Jul 2016 08:54:39 -0400 Subject: [PATCH] Sketched out the generic interface for a disk, documenting it and the tape interface while I'm here. --- .../Clock Signal.xcodeproj/project.pbxproj | 16 +++++ Storage/Disk/Disk.cpp | 9 +++ Storage/Disk/Disk.hpp | 66 +++++++++++++++++++ Storage/Storage.hpp | 20 ++++++ Storage/Tape/Tape.cpp | 2 +- Storage/Tape/Tape.hpp | 25 +++++-- 6 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 Storage/Disk/Disk.cpp create mode 100644 Storage/Disk/Disk.hpp create mode 100644 Storage/Storage.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 302bceebd..69ac802b5 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ 4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73C7191D036BD90074D992 /* Vic20Document.swift */; }; 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; }; 4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; }; + 4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */; }; 4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; }; 4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; }; 4BB298F11B587D8400A49093 /* start in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E51B587D8300A49093 /* start */; }; @@ -415,6 +416,9 @@ 4B73C7191D036BD90074D992 /* Vic20Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vic20Document.swift; sourceTree = ""; }; 4B73C71C1D036C030074D992 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Vic20Document.xib"; sourceTree = SOURCE_ROOT; }; 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = ""; }; + 4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Disk.cpp; sourceTree = ""; }; + 4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Disk.hpp; sourceTree = ""; }; + 4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = ""; }; 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = ""; }; 4BB297E11B587D8300A49093 /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = AllSuiteA.bin; sourceTree = ""; }; 4BB297E51B587D8300A49093 /* start */ = {isa = PBXFileReference; lastKnownFileType = file; path = " start"; sourceTree = ""; }; @@ -941,7 +945,9 @@ 4B69FB391C4D908A00B5F0AA /* Storage */ = { isa = PBXGroup; children = ( + 4BAB62AA1D3272D200DF5BA0 /* Disk */, 4B69FB3A1C4D908A00B5F0AA /* Tape */, + 4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */, ); name = Storage; path = ../../Storage; @@ -969,6 +975,15 @@ path = Formats; sourceTree = ""; }; + 4BAB62AA1D3272D200DF5BA0 /* Disk */ = { + isa = PBXGroup; + children = ( + 4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */, + 4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */, + ); + path = Disk; + sourceTree = ""; + }; 4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */ = { isa = PBXGroup; children = ( @@ -1818,6 +1833,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */, 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */, 4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */, 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, diff --git a/Storage/Disk/Disk.cpp b/Storage/Disk/Disk.cpp new file mode 100644 index 000000000..f431bba4d --- /dev/null +++ b/Storage/Disk/Disk.cpp @@ -0,0 +1,9 @@ +// +// Disk.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/07/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "Disk.hpp" diff --git a/Storage/Disk/Disk.hpp b/Storage/Disk/Disk.hpp new file mode 100644 index 000000000..614169431 --- /dev/null +++ b/Storage/Disk/Disk.hpp @@ -0,0 +1,66 @@ +// +// Disk.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/07/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Disk_hpp +#define Disk_hpp + +#include +#include "../Storage.hpp" + +namespace Storage { + +/*! + Models a single track on a disk as a series of events, each event being of arbitrary length + and resulting in either a flux transition or the sensing of an index hole. + + Subclasses should implement @c get_next_event. +*/ +class Track { + public: + struct Event { + enum { + IndexHole, FluxTransition + } type; + Time length; + }; + + virtual Event get_next_event() = 0; +}; + +/*! + Models a disk as a collection of tracks, providing a range of possible track positions and allowing + a point sampling of the track beneath any of those positions (if any). + + The intention is not that tracks necessarily be evenly spaced; a head_position_count of 3 wih track + A appearing in positions 0 and 1, and track B appearing in position 2 is an appropriate use of this API + if it matches the media. + + The track returned is point sampled only; if a particular disk drive has a sufficiently large head to + pick up multiple tracks at once then the drive responsible for asking for multiple tracks and for + merging the results. +*/ +class Disk { + public: + + /*! + Returns the number of discrete positions that this disk uses to model its complete surface area. + + This is not necessarily a track count. There is no implicit guarantee that every position will + return a distinct track, or — if the media is holeless — will return any track at all. + */ + virtual unsigned int get_head_position_count() = 0; + + /*! + Returns the @c Track at @c position if there are any detectable events there; returns @c nullptr otherwise. + */ + virtual std::shared_ptr get_track_at_position(unsigned int position) = 0; +}; + +} + +#endif /* Disk_hpp */ diff --git a/Storage/Storage.hpp b/Storage/Storage.hpp new file mode 100644 index 000000000..ac65da093 --- /dev/null +++ b/Storage/Storage.hpp @@ -0,0 +1,20 @@ +// +// Storage.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/07/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Storage_hpp +#define Storage_hpp + +namespace Storage { + +struct Time { + unsigned int length, clock_rate; +}; + +} + +#endif /* Storage_h */ diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index b1a9babde..822093b1c 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -10,7 +10,7 @@ using namespace Storage; -void Tape::seek(Tape::Time seek_time) +void Tape::seek(Time seek_time) { // TODO: as best we can } diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index eecae2862..47babe011 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -11,15 +11,23 @@ #include #include "../../SignalProcessing/Stepper.hpp" +#include "../Storage.hpp" namespace Storage { +/*! + Models a tape as a sequence of pulses, each pulse being of arbitrary length and described + by their relationship with zero: + - high pulses exit from zero upward before returning to it; + - low pulses exit from zero downward before returning to it; + - zero pulses run along zero. + + Subclasses should implement at least @c get_next_pulse and @c reset to provide a serial feeding + of pulses and the ability to return to the start of the feed. They may also implement @c seek if + a better implementation than a linear search from the @c reset time can be implemented. +*/ class Tape { public: - struct Time { - unsigned int length, clock_rate; - }; - struct Pulse { enum { High, Low, Zero @@ -30,9 +38,16 @@ class Tape { virtual Pulse get_next_pulse() = 0; virtual void reset() = 0; - virtual void seek(Time seek_time); + virtual void seek(Time seek_time); // TODO }; +/*! + Provides a helper for: (i) retaining a reference to a tape; and (ii) running the tape at a certain + input clock rate. + + Will call @c process_input_pulse instantaneously upon reaching *the end* of a pulse. Therefore a subclass + can decode pulses into data within process_input_pulse, using the supplied pulse's @c length and @c type. +*/ class TapePlayer { public: TapePlayer(unsigned int input_clock_rate);