diff --git a/Analyser/Static/StaticAnalyser.cpp b/Analyser/Static/StaticAnalyser.cpp index bbd49c8d2..4d4801b98 100644 --- a/Analyser/Static/StaticAnalyser.cpp +++ b/Analyser/Static/StaticAnalyser.cpp @@ -46,6 +46,7 @@ #include "../../Storage/Disk/DiskImage/Formats/NIB.hpp" #include "../../Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp" #include "../../Storage/Disk/DiskImage/Formats/SSD.hpp" +#include "../../Storage/Disk/DiskImage/Formats/ST.hpp" #include "../../Storage/Disk/DiskImage/Formats/WOZ.hpp" // Mass Storage Devices (i.e. usually, hard disks) @@ -145,6 +146,7 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform:: Format("sg", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Sega) // SG Format("sms", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Sega) // SMS Format("ssd", result.disks, Disk::DiskImageHolder, TargetPlatform::Acorn) // SSD + Format("st", result.disks, Disk::DiskImageHolder, TargetPlatform::AtariST) // ST Format("tap", result.tapes, Tape::CommodoreTAP, TargetPlatform::Commodore) // TAP (Commodore) Format("tap", result.tapes, Tape::OricTAP, TargetPlatform::Oric) // TAP (Oric) Format("tsx", result.tapes, Tape::TZX, TargetPlatform::MSX) // TSX diff --git a/Machines/Atari/ST/AtariST.cpp b/Machines/Atari/ST/AtariST.cpp index e3683e4d1..fb9fa8f7f 100644 --- a/Machines/Atari/ST/AtariST.cpp +++ b/Machines/Atari/ST/AtariST.cpp @@ -71,8 +71,8 @@ class ConcreteMachine: Memory::Fuzz(ram_); std::vector rom_descriptions = { -// {"AtariST", "the UK TOS 1.00 ROM", "tos100.img", 192*1024, 0x1a586c64} - {"AtariST", "the UK TOS 1.04 ROM", "tos104.img", 192*1024, 0xa50d1d43} + {"AtariST", "the UK TOS 1.00 ROM", "tos100.img", 192*1024, 0x1a586c64} +// {"AtariST", "the UK TOS 1.04 ROM", "tos104.img", 192*1024, 0xa50d1d43} }; const auto roms = rom_fetcher(rom_descriptions); if(!roms[0]) { diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 268b25464..e5320b768 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -707,6 +707,8 @@ 4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; }; 4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8FE21F1DA19D7C0090D3CE /* Atari2600OptionsPanel.swift */; }; 4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */; }; + 4BE0A3EE237BB170002AB46F /* ST.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE0A3EC237BB170002AB46F /* ST.cpp */; }; + 4BE0A3EF237BB170002AB46F /* ST.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE0A3EC237BB170002AB46F /* ST.cpp */; }; 4BE76CF922641ED400ACD6FA /* QLTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BE76CF822641ED300ACD6FA /* QLTests.mm */; }; 4BE90FFD22D5864800FB464D /* MacintoshVideoTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BE90FFC22D5864800FB464D /* MacintoshVideoTests.mm */; }; 4BE9A6B11EDE293000CBCB47 /* zexdoc.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BE9A6B01EDE293000CBCB47 /* zexdoc.com */; }; @@ -1573,6 +1575,8 @@ 4BDB3D8522833321002D3CEE /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = ""; }; 4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMMachine.hpp; sourceTree = ""; }; 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = ""; }; + 4BE0A3EC237BB170002AB46F /* ST.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ST.cpp; sourceTree = ""; }; + 4BE0A3ED237BB170002AB46F /* ST.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ST.hpp; sourceTree = ""; }; 4BE3231220532443006EF799 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; 4BE32313205327D7006EF799 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; 4BE32314205328FF006EF799 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; @@ -2124,36 +2128,38 @@ isa = PBXGroup; children = ( 4B45188D1F75FD1B00926311 /* AcornADF.cpp */, - 4B0333AD2094081A0050B93D /* AppleDSK.cpp */, - 4B45188F1F75FD1B00926311 /* CPCDSK.cpp */, - 4B4518911F75FD1B00926311 /* D64.cpp */, - 4BAF2B4C2004580C00480230 /* DMK.cpp */, - 4B4518931F75FD1B00926311 /* G64.cpp */, - 4B4518951F75FD1B00926311 /* HFE.cpp */, - 4BB4BFAE22A42F290069048D /* MacintoshIMG.cpp */, - 4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */, - 4BC131782346DF2B00E4FF3D /* MSA.cpp */, - 4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */, - 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */, - 4B4518971F75FD1B00926311 /* OricMFMDSK.cpp */, - 4B4518991F75FD1B00926311 /* SSD.cpp */, - 4B6ED2EE208E2F8A0047B343 /* WOZ.cpp */, 4B45188E1F75FD1B00926311 /* AcornADF.hpp */, + 4B0333AD2094081A0050B93D /* AppleDSK.cpp */, 4B0333AE2094081A0050B93D /* AppleDSK.hpp */, + 4B45188F1F75FD1B00926311 /* CPCDSK.cpp */, 4B4518901F75FD1B00926311 /* CPCDSK.hpp */, + 4B4518911F75FD1B00926311 /* D64.cpp */, 4B4518921F75FD1B00926311 /* D64.hpp */, + 4BAF2B4C2004580C00480230 /* DMK.cpp */, 4BAF2B4D2004580C00480230 /* DMK.hpp */, + 4B4518931F75FD1B00926311 /* G64.cpp */, 4B4518941F75FD1B00926311 /* G64.hpp */, + 4B4518951F75FD1B00926311 /* HFE.cpp */, 4B4518961F75FD1B00926311 /* HFE.hpp */, + 4BB4BFAE22A42F290069048D /* MacintoshIMG.cpp */, 4BB4BFAF22A42F290069048D /* MacintoshIMG.hpp */, + 4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */, 4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */, + 4BC131782346DF2B00E4FF3D /* MSA.cpp */, 4BC131792346DF2B00E4FF3D /* MSA.hpp */, + 4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */, 4BEBFB4C2002C4BF000708CC /* MSXDSK.hpp */, + 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */, 4B0F94FD208C1A1600FE41D9 /* NIB.hpp */, + 4B4518971F75FD1B00926311 /* OricMFMDSK.cpp */, 4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */, + 4B4518991F75FD1B00926311 /* SSD.cpp */, 4B45189A1F75FD1B00926311 /* SSD.hpp */, - 4B6ED2EF208E2F8A0047B343 /* WOZ.hpp */, + 4BE0A3EC237BB170002AB46F /* ST.cpp */, + 4BE0A3ED237BB170002AB46F /* ST.hpp */, 4BFDD7891F7F2DB4008579B9 /* Utility */, + 4B6ED2EE208E2F8A0047B343 /* WOZ.cpp */, + 4B6ED2EF208E2F8A0047B343 /* WOZ.hpp */, ); path = Formats; sourceTree = ""; @@ -4196,6 +4202,7 @@ 4BBB70A5202011C2002FE009 /* MultiMediaTarget.cpp in Sources */, 4B8318BC22D3E588006DB630 /* DisplayMetrics.cpp in Sources */, 4B1B88BD202E3D3D00B67DFF /* MultiMachine.cpp in Sources */, + 4BE0A3EF237BB170002AB46F /* ST.cpp in Sources */, 4B055A971FAE85BB0060FFFF /* ZX8081.cpp in Sources */, 4B055AAD1FAE85FD0060FFFF /* PCMTrack.cpp in Sources */, 4BD67DD1209BF27B00AB2146 /* Encoder.cpp in Sources */, @@ -4351,6 +4358,7 @@ 4BD67DD0209BF27B00AB2146 /* Encoder.cpp in Sources */, 4BAE495920328897004BE78E /* ZX8081OptionsPanel.swift in Sources */, 4B89451A201967B4007DE474 /* ConfidenceSummary.cpp in Sources */, + 4BE0A3EE237BB170002AB46F /* ST.cpp in Sources */, 4B54C0C51F8D91D90050900F /* Keyboard.cpp in Sources */, 4BEE149A227FC0EA00133682 /* IWM.cpp in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Info.plist b/OSBindings/Mac/Clock Signal/Info.plist index 20f8b00df..9d46facbf 100644 --- a/OSBindings/Mac/Clock Signal/Info.plist +++ b/OSBindings/Mac/Clock Signal/Info.plist @@ -393,6 +393,7 @@ CFBundleTypeExtensions msa + st CFBundleTypeIconFile floppy35.png diff --git a/Storage/Disk/DiskImage/Formats/MFMSectorDump.cpp b/Storage/Disk/DiskImage/Formats/MFMSectorDump.cpp index 995607273..8e7359d4f 100644 --- a/Storage/Disk/DiskImage/Formats/MFMSectorDump.cpp +++ b/Storage/Disk/DiskImage/Formats/MFMSectorDump.cpp @@ -22,10 +22,11 @@ void MFMSectorDump::set_geometry(int sectors_per_track, uint8_t sector_size, uin } std::shared_ptr MFMSectorDump::get_track_at_position(Track::Address address) { - uint8_t sectors[(128 << sector_size_)*sectors_per_track_]; + if(address.head >= get_head_count()) return nullptr; + if(address.position.as_largest() >= get_maximum_head_position().as_largest()) return nullptr; - if(address.head > 1) return nullptr; - long file_offset = get_file_offset_for_position(address); + uint8_t sectors[(128 << sector_size_)*sectors_per_track_]; + const long file_offset = get_file_offset_for_position(address); { std::lock_guard lock_guard(file_.get_file_access_mutex()); @@ -45,7 +46,7 @@ void MFMSectorDump::set_tracks(const std::map(sectors_per_track_-1), sector_size_, is_double_density_); - long file_offset = get_file_offset_for_position(track.first); + const long file_offset = get_file_offset_for_position(track.first); std::lock_guard lock_guard(file_.get_file_access_mutex()); file_.ensure_is_at_least_length(file_offset); diff --git a/Storage/Disk/DiskImage/Formats/SSD.cpp b/Storage/Disk/DiskImage/Formats/SSD.cpp index 71cc6ba0b..7e455e69e 100644 --- a/Storage/Disk/DiskImage/Formats/SSD.cpp +++ b/Storage/Disk/DiskImage/Formats/SSD.cpp @@ -25,7 +25,7 @@ SSD::SSD(const std::string &file_name) : MFMSectorDump(file_name) { // this has two heads if the suffix is .dsd, one if it's .ssd head_count_ = (tolower(file_name[file_name.size() - 3]) == 'd') ? 2 : 1; - track_count_ = int(file_.stats().st_size / (256 * 10)); + track_count_ = int(file_.stats().st_size / (256 * 10 * head_count_)); if(track_count_ < 40) track_count_ = 40; else if(track_count_ < 80) track_count_ = 80; diff --git a/Storage/Disk/DiskImage/Formats/ST.cpp b/Storage/Disk/DiskImage/Formats/ST.cpp new file mode 100644 index 000000000..fd1a251f2 --- /dev/null +++ b/Storage/Disk/DiskImage/Formats/ST.cpp @@ -0,0 +1,42 @@ +// +// ST.cpp +// Clock Signal +// +// Created by Thomas Harte on 12/11/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#include "ST.hpp" + +namespace { + static const int sectors_per_track = 10; + static const int sector_size = 2; +} + +using namespace Storage::Disk; + +ST::ST(const std::string &file_name) : MFMSectorDump(file_name) { + // Very loose validation: the file needs to be a whole number of tracks, + // and not more than 160 of them. + const auto stats = file_.stats(); + if(stats.st_size % 512*10) throw Error::InvalidFormat; + if(stats.st_size > 512*10*160) throw Error::InvalidFormat; + + // Head count: 2 if there are more than 80 tracks. Otherwise 1. + head_count_ = (stats.st_size >= 512 * 10 * 80) ? 2 : 1; + track_count_ = std::max(80, int(stats.st_size / (512 * 10 * head_count_))); + + set_geometry(sectors_per_track, sector_size, 1, true); +} + +HeadPosition ST::get_maximum_head_position() { + return HeadPosition(track_count_); +} + +int ST::get_head_count() { + return head_count_; +} + +long ST::get_file_offset_for_position(Track::Address address) { + return (address.position.as_int() * head_count_ + address.head) * 512 * sectors_per_track; +} diff --git a/Storage/Disk/DiskImage/Formats/ST.hpp b/Storage/Disk/DiskImage/Formats/ST.hpp new file mode 100644 index 000000000..2b34d33b1 --- /dev/null +++ b/Storage/Disk/DiskImage/Formats/ST.hpp @@ -0,0 +1,43 @@ +// +// ST.hpp +// Clock Signal +// +// Created by Thomas Harte on 12/11/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#ifndef ST_hpp +#define ST_hpp + +#include "MFMSectorDump.hpp" + +namespace Storage { +namespace Disk { + +/*! + Provides a @c Disk containing an ST disk image: a decoded sector dump of an Atari ST disk. +*/ +class ST: public MFMSectorDump { + public: + /*! + Construct an @c ST containing content from the file with name @c file_name. + + @throws Storage::FileHolder::Error::CantOpen if this file can't be opened. + @throws Error::InvalidFormat if the file doesn't appear to contain a .ST format image. + */ + ST(const std::string &file_name); + + HeadPosition get_maximum_head_position() override; + int get_head_count() override; + + private: + long get_file_offset_for_position(Track::Address address) override; + + int head_count_; + int track_count_; +}; + +} +} + +#endif /* ST_hpp */