diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 3728929e5..6628b060a 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -357,6 +357,7 @@ 4BF1354C1D6D2C300054B2EA /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF1354A1D6D2C300054B2EA /* StaticAnalyser.cpp */; }; 4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8295B1D8F048B001BAE39 /* MFM.cpp */; }; 4BF829601D8F3C87001BAE39 /* CRC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8295E1D8F3C87001BAE39 /* CRC.cpp */; }; + 4BF829631D8F536B001BAE39 /* SSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829611D8F536B001BAE39 /* SSD.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -811,6 +812,8 @@ 4BF8295C1D8F048B001BAE39 /* MFM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MFM.hpp; path = Encodings/MFM.hpp; sourceTree = ""; }; 4BF8295E1D8F3C87001BAE39 /* CRC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CRC.cpp; path = ../../NumberTheory/CRC.cpp; sourceTree = ""; }; 4BF8295F1D8F3C87001BAE39 /* CRC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRC.hpp; path = ../../NumberTheory/CRC.hpp; sourceTree = ""; }; + 4BF829611D8F536B001BAE39 /* SSD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SSD.cpp; sourceTree = ""; }; + 4BF829621D8F536B001BAE39 /* SSD.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SSD.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1117,6 +1120,8 @@ 4BAB62B41D327F7E00DF5BA0 /* G64.hpp */, 4B4C836E1D4F623200CD541F /* D64.cpp */, 4B4C836F1D4F623200CD541F /* D64.hpp */, + 4BF829611D8F536B001BAE39 /* SSD.cpp */, + 4BF829621D8F536B001BAE39 /* SSD.hpp */, ); path = Formats; sourceTree = ""; @@ -2112,6 +2117,7 @@ 4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */, 4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */, 4B1E85751D170228001EF87D /* Typer.cpp in Sources */, + 4BF829631D8F536B001BAE39 /* SSD.cpp in Sources */, 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */, 4BAB62B81D3302CA00DF5BA0 /* PCMTrack.cpp in Sources */, 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */, diff --git a/StaticAnalyser/StaticAnalyser.cpp b/StaticAnalyser/StaticAnalyser.cpp index 2f57788f2..98d799b05 100644 --- a/StaticAnalyser/StaticAnalyser.cpp +++ b/StaticAnalyser/StaticAnalyser.cpp @@ -22,6 +22,7 @@ // Disks #include "../Storage/Disk/Formats/D64.hpp" #include "../Storage/Disk/Formats/G64.hpp" +#include "../Storage/Disk/Formats/SSD.hpp" // Tapes #include "../Storage/Tape/Formats/CommodoreTAP.hpp" @@ -81,6 +82,7 @@ std::list StaticAnalyser::GetTargets(const char *file_name) Format("a26", cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // A26 Format("bin", cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // BIN Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64 + Format("dsd", disks, Disk::SSD, TargetPlatform::Acorn) // DSD Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64 // PRG @@ -98,8 +100,8 @@ std::list StaticAnalyser::GetTargets(const char *file_name) } } - // ROM Format("rom", cartridges, Cartridge::BinaryDump, TargetPlatform::Acorn) // ROM + Format("ssd", disks, Disk::SSD, TargetPlatform::Acorn) // SSD Format("tap", tapes, Tape::CommodoreTAP, TargetPlatform::Commodore) // TAP Format("uef", tapes, Tape::UEF, TargetPlatform::Acorn) // UEF (tape) diff --git a/Storage/Disk/Disk.hpp b/Storage/Disk/Disk.hpp index c17712b85..50466161e 100644 --- a/Storage/Disk/Disk.hpp +++ b/Storage/Disk/Disk.hpp @@ -73,10 +73,15 @@ class Disk { */ virtual unsigned int get_head_position_count() = 0; + /*! + Returns the number of heads (and, therefore, impliedly surfaces) available on this disk. + */ + virtual unsigned int get_head_count() { return 1; } + /*! 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; + virtual std::shared_ptr get_track_at_position(unsigned int head, unsigned int position) = 0; }; } diff --git a/Storage/Disk/DiskDrive.cpp b/Storage/Disk/DiskDrive.cpp index 681a9e94d..f69788950 100644 --- a/Storage/Disk/DiskDrive.cpp +++ b/Storage/Disk/DiskDrive.cpp @@ -60,7 +60,7 @@ void Drive::step(int direction) void Drive::set_track(Time initial_offset) { - _track = _disk->get_track_at_position((unsigned int)_head_position); + _track = _disk->get_track_at_position(0, (unsigned int)_head_position); // TODO: probably a better implementation of the empty track? Time offset; if(_track && _time_into_track.length > 0) diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM.cpp index b8704946a..6b7bd7102 100644 --- a/Storage/Disk/Encodings/MFM.cpp +++ b/Storage/Disk/Encodings/MFM.cpp @@ -191,7 +191,7 @@ template std::shared_ptr while(shifter.segment.data.size() < expected_track_bytes) shifter.add_byte(0x00); - shifter.segment.number_of_bits = shifter.segment.data.size() * 8; + shifter.segment.number_of_bits = (unsigned int)(shifter.segment.data.size() * 8); return std::shared_ptr(new Storage::Disk::PCMTrack(std::move(shifter.segment))); } diff --git a/Storage/Disk/Formats/D64.cpp b/Storage/Disk/Formats/D64.cpp index af406c253..f0397b10b 100644 --- a/Storage/Disk/Formats/D64.cpp +++ b/Storage/Disk/Formats/D64.cpp @@ -53,10 +53,10 @@ unsigned int D64::get_head_position_count() return _number_of_tracks*2; } -std::shared_ptr D64::get_track_at_position(unsigned int position) +std::shared_ptr D64::get_track_at_position(unsigned int head, unsigned int position) { - // every other track is missing - if(position&1) + // every other track is missing, as is any head above 0 + if(position&1 || head) return std::shared_ptr(); // figure out where this track starts on the disk diff --git a/Storage/Disk/Formats/D64.hpp b/Storage/Disk/Formats/D64.hpp index 93c4d4cb5..7b3b20291 100644 --- a/Storage/Disk/Formats/D64.hpp +++ b/Storage/Disk/Formats/D64.hpp @@ -35,7 +35,7 @@ class D64: public Disk { // implemented to satisfy @c Disk unsigned int get_head_position_count(); - std::shared_ptr get_track_at_position(unsigned int position); + std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); private: FILE *_file; diff --git a/Storage/Disk/Formats/G64.cpp b/Storage/Disk/Formats/G64.cpp index 920ac856f..86df3022f 100644 --- a/Storage/Disk/Formats/G64.cpp +++ b/Storage/Disk/Formats/G64.cpp @@ -54,13 +54,14 @@ unsigned int G64::get_head_position_count() return _number_of_tracks > 84 ? _number_of_tracks : 84; } -std::shared_ptr G64::get_track_at_position(unsigned int position) +std::shared_ptr G64::get_track_at_position(unsigned int head, unsigned int position) { std::shared_ptr resulting_track; // if there's definitely no track here, return the empty track // (TODO: should be supplying one with an index hole?) if(position >= _number_of_tracks) return resulting_track; + if(head >= 1) return resulting_track; // seek to this track's entry in the track table fseek(_file, (long)((position * 4) + 0xc), SEEK_SET); diff --git a/Storage/Disk/Formats/G64.hpp b/Storage/Disk/Formats/G64.hpp index 82ab9ae97..35db52efb 100644 --- a/Storage/Disk/Formats/G64.hpp +++ b/Storage/Disk/Formats/G64.hpp @@ -37,7 +37,7 @@ class G64: public Disk { // implemented to satisfy @c Disk unsigned int get_head_position_count(); - std::shared_ptr get_track_at_position(unsigned int position); + std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); private: FILE *_file; diff --git a/Storage/Disk/Formats/SSD.cpp b/Storage/Disk/Formats/SSD.cpp new file mode 100644 index 000000000..490d5ce9d --- /dev/null +++ b/Storage/Disk/Formats/SSD.cpp @@ -0,0 +1,51 @@ +// +// SSD.cpp +// Clock Signal +// +// Created by Thomas Harte on 18/09/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "SSD.hpp" + +#include + +using namespace Storage::Disk; + +SSD::SSD(const char *file_name) : _file(nullptr) +{ + struct stat file_stats; + stat(file_name, &file_stats); + + // very loose validation: the file needs to be a multiple of 256 bytes + // and not ungainly large + + if(file_stats.st_size & 255) throw ErrorNotSSD; + if(file_stats.st_size < 512) throw ErrorNotSSD; + if(file_stats.st_size > 800*256) throw ErrorNotSSD; + + _file = fopen(file_name, "rb"); + + if(!_file) throw ErrorCantOpen; +} + +SSD::~SSD() +{ + if(_file) fclose(_file); +} + +unsigned int SSD::get_head_position_count() +{ + return 1; +} + +unsigned int SSD::get_head_count() +{ + return 1; +} + +std::shared_ptr SSD::get_track_at_position(unsigned int head, unsigned int position) +{ + std::shared_ptr track; + return track; +} diff --git a/Storage/Disk/Formats/SSD.hpp b/Storage/Disk/Formats/SSD.hpp new file mode 100644 index 000000000..a45a21721 --- /dev/null +++ b/Storage/Disk/Formats/SSD.hpp @@ -0,0 +1,48 @@ +// +// SSD.hpp +// Clock Signal +// +// Created by Thomas Harte on 18/09/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef SSD_hpp +#define SSD_hpp + +#include "../Disk.hpp" + +namespace Storage { +namespace Disk { + +/*! + Provies a @c Disk containing a DSD or SSD disk image — a decoded sector dump of an Acorn DFS disk. +*/ +class SSD: public Disk { + public: + /*! + Construct a @c D64 containing content from the file with name @c file_name. + + @throws ErrorCantOpen if this file can't be opened. + @throws ErrorNotD64 if the file doesn't appear to contain a .D64 format image. + */ + SSD(const char *file_name); + ~SSD(); + + enum { + ErrorCantOpen, + ErrorNotSSD, + }; + + // implemented to satisfy @c Disk + unsigned int get_head_position_count(); + unsigned int get_head_count(); + std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); + + private: + FILE *_file; +}; + +} +} + +#endif /* SSD_hpp */