diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 7f12e2183..8876fcf48 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -458,6 +458,7 @@ 4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */; }; 4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BFCA1281ECBE7A700AC40C1 /* zexall.com */; }; 4BFCA12B1ECBE7C400AC40C1 /* ZexallTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */; }; + 4BFDD78C1F7F2DB4008579B9 /* ImplicitSectors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1119,6 +1120,8 @@ 4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachineZ80.mm; sourceTree = ""; }; 4BFCA1281ECBE7A700AC40C1 /* zexall.com */ = {isa = PBXFileReference; lastKnownFileType = file; name = zexall.com; path = Zexall/zexall.com; sourceTree = ""; }; 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZexallTests.swift; sourceTree = ""; }; + 4BFDD78A1F7F2DB4008579B9 /* ImplicitSectors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ImplicitSectors.hpp; sourceTree = ""; }; + 4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImplicitSectors.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1469,6 +1472,7 @@ 4B45188C1F75FD1B00926311 /* Formats */ = { isa = PBXGroup; children = ( + 4BFDD7891F7F2DB4008579B9 /* Utility */, 4B45188D1F75FD1B00926311 /* AcornADF.cpp */, 4B45188E1F75FD1B00926311 /* AcornADF.hpp */, 4B45188F1F75FD1B00926311 /* CPCDSK.cpp */, @@ -2456,6 +2460,15 @@ path = ../../ClockReceiver; sourceTree = ""; }; + 4BFDD7891F7F2DB4008579B9 /* Utility */ = { + isa = PBXGroup; + children = ( + 4BFDD78A1F7F2DB4008579B9 /* ImplicitSectors.hpp */, + 4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */, + ); + path = Utility; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -2990,6 +3003,7 @@ 4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */, 4B83348A1F5DB94B0097E338 /* IRQDelegatePortHandler.cpp in Sources */, 4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */, + 4BFDD78C1F7F2DB4008579B9 /* ImplicitSectors.cpp in Sources */, 4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */, 4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */, 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */, diff --git a/Storage/Disk/DiskImage/Formats/AcornADF.cpp b/Storage/Disk/DiskImage/Formats/AcornADF.cpp index 3b4a1c7c4..2d1893b63 100644 --- a/Storage/Disk/DiskImage/Formats/AcornADF.cpp +++ b/Storage/Disk/DiskImage/Formats/AcornADF.cpp @@ -8,11 +8,7 @@ #include "AcornADF.hpp" -#include -#include "../../Encodings/MFM/Constants.hpp" -#include "../../Encodings/MFM/Encoder.hpp" -#include "../../Track/TrackSerialiser.hpp" -#include "../../Encodings/MFM/SegmentParser.hpp" +#include "Utility/ImplicitSectors.hpp" namespace { static const unsigned int sectors_per_track = 16; @@ -57,54 +53,28 @@ long AcornADF::get_file_offset_for_position(unsigned int head, unsigned int posi } std::shared_ptr AcornADF::get_track_at_position(unsigned int head, unsigned int position) { - std::shared_ptr track; + uint8_t sectors[bytes_per_sector*sectors_per_track]; - if(head >= 2) return track; + if(head > 1) return nullptr; long file_offset = get_file_offset_for_position(head, position); - std::vector sectors; { std::lock_guard lock_guard(file_access_mutex_); fseek(file_, file_offset, SEEK_SET); - - for(unsigned int sector = 0; sector < sectors_per_track; sector++) { - Storage::Encodings::MFM::Sector new_sector; - new_sector.address.track = (uint8_t)position; - new_sector.address.side = (uint8_t)head; - new_sector.address.sector = (uint8_t)sector; - new_sector.size = sector_size; - - new_sector.data.resize(bytes_per_sector); - fread(&new_sector.data[0], 1, bytes_per_sector, file_); - if(feof(file_)) - break; - - sectors.push_back(std::move(new_sector)); - } + fread(sectors, 1, sizeof(sectors), file_); } - if(sectors.size()) return Storage::Encodings::MFM::GetMFMTrackWithSectors(sectors); - - return track; + return track_for_sectors(sectors, (uint8_t)position, (uint8_t)head, 0, sector_size, true); } void AcornADF::set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr &track) { - std::map sectors = - Storage::Encodings::MFM::sectors_from_segment( - Storage::Disk::track_serialisation(*track, Storage::Encodings::MFM::MFMBitLength), - true); - - std::vector parsed_track(sectors_per_track*bytes_per_sector, 0); - for(auto &pair : sectors) { - if(pair.second.address.sector >= sectors_per_track) continue; - if(pair.second.size != sector_size) continue; - memcpy(&parsed_track[pair.second.address.sector * bytes_per_sector], pair.second.data.data(), std::min(pair.second.data.size(), bytes_per_sector)); - } + uint8_t parsed_track[bytes_per_sector*sectors_per_track]; + decode_sectors(*track, parsed_track, 0, sectors_per_track-1, sector_size, true); long file_offset = get_file_offset_for_position(head, position); std::lock_guard lock_guard(file_access_mutex_); ensure_file_is_at_least_length(file_offset); fseek(file_, file_offset, SEEK_SET); - fwrite(parsed_track.data(), 1, parsed_track.size(), file_); + fwrite(parsed_track, 1, sizeof(parsed_track), file_); } diff --git a/Storage/Disk/DiskImage/Formats/SSD.cpp b/Storage/Disk/DiskImage/Formats/SSD.cpp index f09e2f742..4763622e2 100644 --- a/Storage/Disk/DiskImage/Formats/SSD.cpp +++ b/Storage/Disk/DiskImage/Formats/SSD.cpp @@ -8,8 +8,13 @@ #include "SSD.hpp" -#include "../../Encodings/MFM/Encoder.hpp" -#include "../../Encodings/MFM/Parser.hpp" +#include "Utility/ImplicitSectors.hpp" + +namespace { + static const unsigned int sectors_per_track = 10; + static const size_t bytes_per_sector = 256; + static const unsigned int sector_size = 1; +} using namespace Storage::Disk; @@ -46,57 +51,28 @@ long SSD::get_file_offset_for_position(unsigned int head, unsigned int position) } std::shared_ptr SSD::get_track_at_position(unsigned int head, unsigned int position) { - std::shared_ptr track; + uint8_t sectors[bytes_per_sector*sectors_per_track]; - if(head >= head_count_) return track; + if(head >= head_count_) return nullptr; + long file_offset = get_file_offset_for_position(head, position); - std::vector sectors; { std::lock_guard lock_guard(file_access_mutex_); - fseek(file_, get_file_offset_for_position(head, position), SEEK_SET); - - for(int sector = 0; sector < 10; sector++) { - Storage::Encodings::MFM::Sector new_sector; - new_sector.address.track = (uint8_t)position; - new_sector.address.side = 0; - new_sector.address.sector = (uint8_t)sector; - new_sector.size = 1; - - new_sector.data.resize(256); - fread(new_sector.data.data(), 1, 256, file_); - - // zero out if this wasn't present in the disk image; it's still appropriate to put a sector - // on disk because one will have been placed during formatting, but there's no reason to leak - // information from outside the emulated machine's world - if(feof(file_)) memset(new_sector.data.data(), 0, 256); - - sectors.push_back(std::move(new_sector)); - } + fseek(file_, file_offset, SEEK_SET); + fread(sectors, 1, sizeof(sectors), file_); } - if(sectors.size()) return Storage::Encodings::MFM::GetFMTrackWithSectors(sectors); - - return track; + return track_for_sectors(sectors, (uint8_t)position, (uint8_t)head, 0, sector_size, false); } void SSD::set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr &track) { -/* std::vector data; - Storage::Encodings::MFM::Parser parser(false, track); - for(unsigned int c = 0; c < 10; c++) { - Storage::Encodings::MFM::Sector *sector = parser.get_sector(0, (uint8_t)position, (uint8_t)c); - if(sector) { - data.insert(data.end(), sector->data.begin(), sector->data.end()); - } else { - // TODO: what's correct here? Warn the user that whatever has been written to the disk, - // it can no longer be stored as an SSD? If so, warn them by what route? - data.resize(data.size() + 256); - } - } + uint8_t parsed_track[bytes_per_sector*sectors_per_track]; + decode_sectors(*track, parsed_track, 0, sectors_per_track-1, sector_size, false); long file_offset = get_file_offset_for_position(head, position); std::lock_guard lock_guard(file_access_mutex_); ensure_file_is_at_least_length(file_offset); fseek(file_, file_offset, SEEK_SET); - fwrite(data.data(), 1, data.size(), file_);*/ + fwrite(parsed_track, 1, sizeof(parsed_track), file_); } diff --git a/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.cpp b/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.cpp new file mode 100644 index 000000000..9718124de --- /dev/null +++ b/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.cpp @@ -0,0 +1,58 @@ +// +// ImplicitSectors.cpp +// Clock Signal +// +// Created by Thomas Harte on 29/09/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "ImplicitSectors.hpp" + +#include "../../../Encodings/MFM/Sector.hpp" +#include "../../../Encodings/MFM/Encoder.hpp" +#include "../../../Encodings/MFM/Constants.hpp" +#include "../../../Track/TrackSerialiser.hpp" +#include "../../../Encodings/MFM/SegmentParser.hpp" + +using namespace Storage::Disk; + +std::shared_ptr Storage::Disk::track_for_sectors(uint8_t *const source, uint8_t track, uint8_t side, uint8_t first_sector, uint8_t size, bool is_double_density) { + std::vector sectors; + + off_t byte_size = (off_t)(128 << size); + off_t source_pointer = 0; + for(int sector = 0; sector < 10; sector++) { + sectors.emplace_back(); + + Storage::Encodings::MFM::Sector &new_sector = sectors.back(); + new_sector.address.track = track; + new_sector.address.side = size; + new_sector.address.sector = first_sector; + first_sector++; + new_sector.size = size; + + new_sector.data.insert(new_sector.data.begin(), source + source_pointer, source + source_pointer + byte_size); + source_pointer += byte_size; + } + + if(sectors.size()) { + return is_double_density ? Storage::Encodings::MFM::GetMFMTrackWithSectors(sectors) : Storage::Encodings::MFM::GetFMTrackWithSectors(sectors); + } + + return nullptr; +} + +void Storage::Disk::decode_sectors(Track &track, uint8_t *const destination, uint8_t first_sector, uint8_t last_sector, uint8_t sector_size, bool is_double_density) { + std::map sectors = + Storage::Encodings::MFM::sectors_from_segment( + Storage::Disk::track_serialisation(track, is_double_density ? Storage::Encodings::MFM::MFMBitLength : Storage::Encodings::MFM::FMBitLength), + true); + + size_t byte_size = (size_t)(128 << sector_size); + for(auto &pair : sectors) { + if(pair.second.address.sector > last_sector) continue; + if(pair.second.address.sector < first_sector) continue; + if(pair.second.size != sector_size) continue; + memcpy(&destination[pair.second.address.sector * byte_size], pair.second.data.data(), std::min(pair.second.data.size(), byte_size)); + } +} diff --git a/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.hpp b/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.hpp new file mode 100644 index 000000000..e1be6f6e8 --- /dev/null +++ b/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.hpp @@ -0,0 +1,25 @@ +// +// ImplicitSectors.hpp +// Clock Signal +// +// Created by Thomas Harte on 29/09/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef ImplicitSectors_hpp +#define ImplicitSectors_hpp + +#include "../../../Track/Track.hpp" +#include +#include + +namespace Storage { +namespace Disk { + +std::shared_ptr track_for_sectors(uint8_t *const source, uint8_t track, uint8_t side, uint8_t first_sector, uint8_t size, bool is_double_density); +void decode_sectors(Track &track, uint8_t *const destination, uint8_t first_sector, uint8_t last_sector, uint8_t sector_size, bool is_double_density); + +} +} + +#endif /* ImplicitSectors_hpp */