diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index e8dc5bf48..8170445ee 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -92,6 +92,7 @@ 4B8378DF1F33675F005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378DD1F33675F005CA9E4 /* CharacterMapper.cpp */; }; 4B8378E21F336920005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E01F336920005CA9E4 /* CharacterMapper.cpp */; }; 4B8378E51F3378C4005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */; }; + 4B838F1F1F35FDCD0016B5E6 /* CPCDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */; }; 4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */; }; 4B8805F41DCFD22A003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F21DCFD22A003085B1 /* Commodore.cpp */; }; 4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F51DCFF6C9003085B1 /* Commodore.cpp */; }; @@ -618,6 +619,8 @@ 4B8378E11F336920005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CharacterMapper.hpp; path = Oric/CharacterMapper.hpp; sourceTree = ""; }; 4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CharacterMapper.cpp; sourceTree = ""; }; 4B8378E41F3378C4005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CharacterMapper.hpp; sourceTree = ""; }; + 4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPCDSK.cpp; sourceTree = ""; }; + 4B838F1E1F35FDCD0016B5E6 /* CPCDSK.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPCDSK.hpp; sourceTree = ""; }; 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acorn.cpp; path = Parsers/Acorn.cpp; sourceTree = ""; }; 4B8805EF1DCFC99C003085B1 /* Acorn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Acorn.hpp; path = Parsers/Acorn.hpp; sourceTree = ""; }; 4B8805F21DCFD22A003085B1 /* Commodore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Commodore.cpp; path = Parsers/Commodore.cpp; sourceTree = ""; }; @@ -1551,6 +1554,8 @@ 4B5FADBC1DE31D1500AEC565 /* OricMFMDSK.hpp */, 4BF829611D8F536B001BAE39 /* SSD.cpp */, 4BF829621D8F536B001BAE39 /* SSD.hpp */, + 4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */, + 4B838F1E1F35FDCD0016B5E6 /* CPCDSK.hpp */, ); path = Formats; sourceTree = ""; @@ -2751,6 +2756,7 @@ 4BA22B071D8817CE0008C640 /* Disk.cpp in Sources */, 4BEA52661DF3472B007E74F2 /* Speaker.cpp in Sources */, 4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */, + 4B838F1F1F35FDCD0016B5E6 /* CPCDSK.cpp in Sources */, 4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */, 4B4C83701D4F623200CD541F /* D64.cpp in Sources */, 4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */, diff --git a/StaticAnalyser/StaticAnalyser.cpp b/StaticAnalyser/StaticAnalyser.cpp index ff1502617..37e1a6c52 100644 --- a/StaticAnalyser/StaticAnalyser.cpp +++ b/StaticAnalyser/StaticAnalyser.cpp @@ -24,6 +24,7 @@ // Disks #include "../Storage/Disk/Formats/AcornADF.hpp" +#include "../Storage/Disk/Formats/CPCDSK.hpp" #include "../Storage/Disk/Formats/D64.hpp" #include "../Storage/Disk/Formats/G64.hpp" #include "../Storage/Disk/Formats/OricMFMDSK.hpp" @@ -99,7 +100,8 @@ std::list StaticAnalyser::GetTargets(const char *file_name) { Format("csw", tapes, Tape::CSW, TargetPlatform::AllTape) // CSW Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64 Format("dsd", disks, Disk::SSD, TargetPlatform::Acorn) // DSD - Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK + Format("dsk", disks, Disk::CPCDSK, TargetPlatform::AmstradCPC) // DSK (Amstrad CPC) + Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK (Oric) Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64 Format("o", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // O Format("p", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P diff --git a/Storage/Disk/Formats/CPCDSK.cpp b/Storage/Disk/Formats/CPCDSK.cpp new file mode 100644 index 000000000..2e185dda6 --- /dev/null +++ b/Storage/Disk/Formats/CPCDSK.cpp @@ -0,0 +1,126 @@ +// +// CPCDSK.cpp +// Clock Signal +// +// Created by Thomas Harte on 05/08/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "CPCDSK.hpp" + +#include "../Encodings/MFM.hpp" + +using namespace Storage::Disk; + +CPCDSK::CPCDSK(const char *file_name) : + Storage::FileHolder(file_name), is_extended_(false) { + if(!check_signature("MV - CPC", 8)) { + is_extended_ = true; + if(!check_signature("EXTENDED", 8)) + throw ErrorNotCPCDSK; + } + + // Don't really care about about the creator; skip. + fseek(file_, 0x30, SEEK_SET); + head_position_count_ = (unsigned int)fgetc(file_); + head_count_ = (unsigned int)fgetc(file_); + + if(is_extended_) { + for(unsigned int c = 0; c < head_position_count_ * head_count_; c++) { + track_sizes_.push_back((size_t)(fgetc(file_) << 8)); + } + } else { + size_of_a_track_ = fgetc16le(); + } +} + +unsigned int CPCDSK::get_head_position_count() { + return head_position_count_; +} + +unsigned int CPCDSK::get_head_count() { + return head_count_; +} + +bool CPCDSK::get_is_read_only() { + // TODO: allow writing. + return true; +} + +std::shared_ptr CPCDSK::get_uncached_track_at_position(unsigned int head, unsigned int position) { + // Given that thesea are interleaved images, determine which track, chronologically, is being requested. + unsigned int chronological_track = (position * head_count_) + head; + + // All DSK images reserve 0x100 bytes for their headers. + long file_offset = 0x100; + if(is_extended_) { + // Tracks are a variable size in the original DSK file format; sum the lengths + // of all tracks prior to the interesting one to get a file offset. + unsigned int t = 0; + while(t < chronological_track && t < track_sizes_.size()) { + file_offset += track_sizes_[t]; + } + } else { + // Tracks are a fixed size in the original DSK file format. + file_offset += size_of_a_track_ * chronological_track; + } + + // Find the track, and skip the unused part of track information. + fseek(file_, file_offset + 16, SEEK_SET); + + // Grab the track information. + fseek(file_, 5, SEEK_CUR); // skip track number, side number, sector size — each is given per sector + int number_of_sectors = fgetc(file_); + __unused uint8_t gap3_length = (uint8_t)fgetc(file_); + __unused uint8_t filler_byte = (uint8_t)fgetc(file_); + + // Grab the sector information + struct SectorInfo { + uint8_t track; + uint8_t side; + uint8_t sector; + size_t length; + uint8_t status1; + uint8_t status2; + }; + std::vector sector_infos; + while(number_of_sectors--) { + SectorInfo new_sector; + + new_sector.track = (uint8_t)fgetc(file_); + new_sector.side = (uint8_t)fgetc(file_); + new_sector.sector = (uint8_t)fgetc(file_); + new_sector.length = (size_t)(128 << fgetc(file_)); + if(new_sector.length == 0x2000) new_sector.length = 0x1800; + new_sector.status1 = (uint8_t)fgetc(file_); + new_sector.status2 = (uint8_t)fgetc(file_); + fseek(file_, 2, SEEK_CUR); + + sector_infos.push_back(new_sector); + } + + // Get the sectors. + fseek(file_, file_offset + 0x100, SEEK_SET); + if(is_extended_) { + // TODO: everything about extended disk images + } else { + std::vector sectors; + for(auto §or_info : sector_infos) { + Storage::Encodings::MFM::Sector new_sector; + new_sector.track = sector_info.track; + new_sector.side = sector_info.side; + new_sector.sector = sector_info.sector; + new_sector.data.resize(sector_info.length); + fread(new_sector.data.data(), sizeof(uint8_t), sector_info.length, file_); + + // TODO: obey the status bytes, somehow (?) + + sectors.push_back(std::move(new_sector)); + } + + // TODO: supply gay 3 length and filler byte + if(sectors.size()) return Storage::Encodings::MFM::GetMFMTrackWithSectors(sectors); + } + + return nullptr; +} diff --git a/Storage/Disk/Formats/CPCDSK.hpp b/Storage/Disk/Formats/CPCDSK.hpp new file mode 100644 index 000000000..0867dbb84 --- /dev/null +++ b/Storage/Disk/Formats/CPCDSK.hpp @@ -0,0 +1,60 @@ +// +// CPCDSK.hpp +// Clock Signal +// +// Created by Thomas Harte on 05/08/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef CPCDSK_hpp +#define CPCDSK_hpp + +#include "../Disk.hpp" +#include "../../FileHolder.hpp" + +#include + +namespace Storage { +namespace Disk { + +/*! + Provies a @c Disk containing an Amstrad CPC-stype disk image — some arrangement of sectors with status bits. +*/ +class CPCDSK: public Disk, public Storage::FileHolder { + public: + /*! + Construct an @c AcornADF containing content from the file with name @c file_name. + + @throws ErrorCantOpen if this file can't be opened. + @throws ErrorNotAcornADF if the file doesn't appear to contain an Acorn .ADF format image. + */ + CPCDSK(const char *file_name); + + enum { + ErrorNotCPCDSK, + }; + + // implemented to satisfy @c Disk + unsigned int get_head_position_count(); + unsigned int get_head_count(); + bool get_is_read_only(); + + private: + std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position); + + unsigned int head_count_; + unsigned int head_position_count_; + bool is_extended_; + + // Used only for non-extended disks. + long size_of_a_track_; + + // Used only for extended disks. + std::vector track_sizes_; +}; + +} +} + + +#endif /* CPCDSK_hpp */ diff --git a/Storage/Disk/Formats/SSD.cpp b/Storage/Disk/Formats/SSD.cpp index fe570ca36..4903784d5 100644 --- a/Storage/Disk/Formats/SSD.cpp +++ b/Storage/Disk/Formats/SSD.cpp @@ -8,7 +8,6 @@ #include "SSD.hpp" -#include #include "../Encodings/MFM.hpp" using namespace Storage::Disk;