diff --git a/Analyser/Static/MSX/StaticAnalyser.cpp b/Analyser/Static/MSX/StaticAnalyser.cpp index 9e361c460..79a869ccd 100644 --- a/Analyser/Static/MSX/StaticAnalyser.cpp +++ b/Analyser/Static/MSX/StaticAnalyser.cpp @@ -290,6 +290,7 @@ Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &medi target->region = target->media.tapes.empty() ? Target::Region::USA : Target::Region::Europe; // Blindly accept disks for now. + // TODO: how to spot an MSX disk? target->media.disks = media.disks; target->has_disk_drive = !media.disks.empty(); diff --git a/Analyser/Static/StaticAnalyser.cpp b/Analyser/Static/StaticAnalyser.cpp index 163086325..bfb103d3a 100644 --- a/Analyser/Static/StaticAnalyser.cpp +++ b/Analyser/Static/StaticAnalyser.cpp @@ -43,6 +43,7 @@ #include "../../Storage/Disk/DiskImage/Formats/MSXDSK.hpp" #include "../../Storage/Disk/DiskImage/Formats/NIB.hpp" #include "../../Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp" +#include "../../Storage/Disk/DiskImage/Formats/PlusTooBIN.hpp" #include "../../Storage/Disk/DiskImage/Formats/SSD.hpp" #include "../../Storage/Disk/DiskImage/Formats/WOZ.hpp" @@ -91,7 +92,8 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform:: Format("81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // 81 Format("a26", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // A26 Format("adf", result.disks, Disk::DiskImageHolder, TargetPlatform::Acorn) // ADF - Format("bin", result.cartridges, Cartridge::BinaryDump, TargetPlatform::AllCartridge) // BIN + Format("bin", result.cartridges, Cartridge::BinaryDump, TargetPlatform::AllCartridge) // BIN (cartridge dump) + Format("bin", result.disks, Disk::DiskImageHolder, TargetPlatform::Macintosh) // BIN (PlusToo disk image) Format("cas", result.tapes, Tape::CAS, TargetPlatform::MSX) // CAS Format("cdt", result.tapes, Tape::TZX, TargetPlatform::AmstradCPC) // CDT Format("col", result.cartridges, Cartridge::BinaryDump, TargetPlatform::ColecoVision) // COL diff --git a/Components/DiskII/IWM.cpp b/Components/DiskII/IWM.cpp index 8276f2288..ff503a0ff 100644 --- a/Components/DiskII/IWM.cpp +++ b/Components/DiskII/IWM.cpp @@ -25,11 +25,7 @@ namespace { } IWM::IWM(int clock_rate) : - clock_rate_(clock_rate), - drives_{ - {static_cast(clock_rate), 300, 2}, - {static_cast(clock_rate), 300, 2} - } {} + clock_rate_(clock_rate) {} // MARK: - Bus accessors @@ -64,7 +60,7 @@ uint8_t IWM::read(int address) { case ENABLE: /* Read data register. */ printf("Reading data register\n"); - return 0xff; + return 0x00; case Q6: case Q6|ENABLE: { /* @@ -93,7 +89,7 @@ uint8_t IWM::read(int address) { case SEL: // Disk in place. printf("disk in place)\n"); - sense = drives_[active_drive_].has_disk() ? 0x00 : 0x80; + sense = drives_[active_drive_] && drives_[active_drive_]->has_disk() ? 0x00 : 0x80; break; case CA0: // Disk head stepping. @@ -106,12 +102,12 @@ uint8_t IWM::read(int address) { case CA1: // Disk motor running. printf("disk motor running)\n"); - sense = drives_[active_drive_].get_motor_on() ? 0x00 : 0x80; + sense = drives_[active_drive_] && drives_[active_drive_]->get_motor_on() ? 0x00 : 0x80; break; case CA1|SEL: // Head at track 0. printf("head at track 0)\n"); - sense = drives_[active_drive_].get_is_track_zero() ? 0x00 : 0x80; + sense = drives_[active_drive_] && drives_[active_drive_]->get_is_track_zero() ? 0x00 : 0x80; break; case CA1|CA0|SEL: // Tachometer (?) @@ -132,12 +128,13 @@ uint8_t IWM::read(int address) { case CA2|CA1|CA0|SEL: // Drive installed. printf("drive installed)\n"); + sense = drives_[active_drive_] ? 0x00 : 0x80; break; } return (mode_&0x1f) | - (drives_[active_drive_].get_motor_on() ? 0x20 : 0x00) | + (drive_motor_on_ ? 0x20 : 0x00) | sense; } break; @@ -214,13 +211,15 @@ void IWM::access(int address) { case 4: if(address & 1) { - drives_[active_drive_].set_motor_on(true); + drive_motor_on_ = true; + if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(true); } else { // If the 1-second delay is enabled, set up a timer for that. if(!(mode_ & 4)) { cycles_until_motor_off_ = Cycles(clock_rate_); } else { - drives_[active_drive_].set_motor_on(false); + drive_motor_on_ = false; + if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(false); } } break; @@ -228,9 +227,9 @@ void IWM::access(int address) { case 5: { const int new_drive = address & 1; if(new_drive != active_drive_) { - drives_[new_drive].set_motor_on(drives_[active_drive_].get_motor_on()); - drives_[active_drive_].set_motor_on(false); + if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(false); active_drive_ = new_drive; + if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(drive_motor_on_); } } break; } @@ -247,10 +246,22 @@ void IWM::set_select(bool enabled) { // MARK: - Active logic void IWM::run_for(const Cycles cycles) { + // Check for a timeout of the motor-off timer. if(cycles_until_motor_off_ > Cycles(0)) { cycles_until_motor_off_ -= cycles; if(cycles_until_motor_off_ <= Cycles(0)) { - drives_[active_drive_].set_motor_on(false); + drive_motor_on_ = false; + if(drives_[active_drive_]) + drives_[active_drive_]->set_motor_on(false); } } + + // Activity otherwise depends on mode and motor state. + switch(state_ & (Q6 | Q7 | ENABLE)) { + } } + +void IWM::set_drive(int slot, Storage::Disk::Drive *drive) { + drives_[slot] = drive; +} + diff --git a/Components/DiskII/IWM.hpp b/Components/DiskII/IWM.hpp index c63dfe465..764353f81 100644 --- a/Components/DiskII/IWM.hpp +++ b/Components/DiskII/IWM.hpp @@ -38,6 +38,9 @@ class IWM { /// Advances the controller by @c cycles. void run_for(const Cycles cycles); + /// Connects a drive to the IWM. + void set_drive(int slot, Storage::Disk::Drive *drive); + private: const int clock_rate_; @@ -48,7 +51,8 @@ class IWM { int state_ = 0; int active_drive_ = 0; - Storage::Disk::Drive drives_[2]; + Storage::Disk::Drive *drives_[2] = {nullptr, nullptr}; + bool drive_motor_on_ = false; Cycles cycles_until_motor_off_; diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index c3ee812df..f70f55113 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -110,6 +110,8 @@ 4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */; }; 4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2771EE39306008B7065 /* TestMachine.mm */; }; 4B08A56920D72BEF0016CE5A /* Activity.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B08A56720D72BEF0016CE5A /* Activity.xib */; }; + 4B0C956E22A7109A0015A8F6 /* PlusTooBIN.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0C956C22A7109A0015A8F6 /* PlusTooBIN.cpp */; }; + 4B0C957122A74E880015A8F6 /* SonyDrive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0C956F22A74E880015A8F6 /* SonyDrive.cpp */; }; 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; }; 4B0E04EA1FC9E5DA00F43484 /* CAS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E04E81FC9E5DA00F43484 /* CAS.cpp */; }; 4B0E04EB1FC9E78800F43484 /* CAS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E04E81FC9E5DA00F43484 /* CAS.cpp */; }; @@ -726,6 +728,10 @@ 4B08A2771EE39306008B7065 /* TestMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine.mm; sourceTree = ""; }; 4B08A2791EE3957B008B7065 /* TestMachine+ForSubclassEyesOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TestMachine+ForSubclassEyesOnly.h"; sourceTree = ""; }; 4B08A56820D72BEF0016CE5A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Activity.xib"; sourceTree = SOURCE_ROOT; }; + 4B0C956C22A7109A0015A8F6 /* PlusTooBIN.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PlusTooBIN.cpp; sourceTree = ""; }; + 4B0C956D22A7109A0015A8F6 /* PlusTooBIN.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PlusTooBIN.hpp; sourceTree = ""; }; + 4B0C956F22A74E880015A8F6 /* SonyDrive.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SonyDrive.cpp; sourceTree = ""; }; + 4B0C957022A74E880015A8F6 /* SonyDrive.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SonyDrive.hpp; sourceTree = ""; }; 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRT.cpp; sourceTree = ""; }; 4B0CCC431C62D0B3001CAC5F /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRT.hpp; sourceTree = ""; }; 4B0E04E81FC9E5DA00F43484 /* CAS.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAS.cpp; sourceTree = ""; }; @@ -1945,34 +1951,36 @@ isa = PBXGroup; children = ( 4B45188D1F75FD1B00926311 /* AcornADF.cpp */, - 4B45188E1F75FD1B00926311 /* AcornADF.hpp */, 4B0333AD2094081A0050B93D /* AppleDSK.cpp */, - 4B0333AE2094081A0050B93D /* AppleDSK.hpp */, 4B45188F1F75FD1B00926311 /* CPCDSK.cpp */, - 4B4518901F75FD1B00926311 /* CPCDSK.hpp */, 4B4518911F75FD1B00926311 /* D64.cpp */, - 4B4518921F75FD1B00926311 /* D64.hpp */, 4BB4BFAE22A42F290069048D /* DiskCopy42.cpp */, - 4BB4BFAF22A42F290069048D /* DiskCopy42.hpp */, 4BAF2B4C2004580C00480230 /* DMK.cpp */, - 4BAF2B4D2004580C00480230 /* DMK.hpp */, 4B4518931F75FD1B00926311 /* G64.cpp */, - 4B4518941F75FD1B00926311 /* G64.hpp */, 4B4518951F75FD1B00926311 /* HFE.cpp */, - 4B4518961F75FD1B00926311 /* HFE.hpp */, 4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */, - 4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */, 4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */, - 4BEBFB4C2002C4BF000708CC /* MSXDSK.hpp */, 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */, - 4B0F94FD208C1A1600FE41D9 /* NIB.hpp */, 4B4518971F75FD1B00926311 /* OricMFMDSK.cpp */, - 4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */, + 4B0C956C22A7109A0015A8F6 /* PlusTooBIN.cpp */, 4B4518991F75FD1B00926311 /* SSD.cpp */, - 4B45189A1F75FD1B00926311 /* SSD.hpp */, - 4BFDD7891F7F2DB4008579B9 /* Utility */, 4B6ED2EE208E2F8A0047B343 /* WOZ.cpp */, + 4B45188E1F75FD1B00926311 /* AcornADF.hpp */, + 4B0333AE2094081A0050B93D /* AppleDSK.hpp */, + 4B4518901F75FD1B00926311 /* CPCDSK.hpp */, + 4B4518921F75FD1B00926311 /* D64.hpp */, + 4BB4BFAF22A42F290069048D /* DiskCopy42.hpp */, + 4BAF2B4D2004580C00480230 /* DMK.hpp */, + 4B4518941F75FD1B00926311 /* G64.hpp */, + 4B4518961F75FD1B00926311 /* HFE.hpp */, + 4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */, + 4BEBFB4C2002C4BF000708CC /* MSXDSK.hpp */, + 4B0F94FD208C1A1600FE41D9 /* NIB.hpp */, + 4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */, + 4B0C956D22A7109A0015A8F6 /* PlusTooBIN.hpp */, + 4B45189A1F75FD1B00926311 /* SSD.hpp */, 4B6ED2EF208E2F8A0047B343 /* WOZ.hpp */, + 4BFDD7891F7F2DB4008579B9 /* Utility */, ); path = Formats; sourceTree = ""; @@ -3104,6 +3112,8 @@ 4BCE0059227CFFCA000CA200 /* Macintosh.hpp */, 4BD0692B22828A2D00D2A54F /* RealTimeClock.hpp */, 4BCE005F227D39AB000CA200 /* Video.hpp */, + 4B0C956F22A74E880015A8F6 /* SonyDrive.cpp */, + 4B0C957022A74E880015A8F6 /* SonyDrive.hpp */, ); path = Macintosh; sourceTree = ""; @@ -4073,6 +4083,7 @@ 4B30512D1D989E2200B4FED8 /* Drive.cpp in Sources */, 4BCE005D227D30CC000CA200 /* MemoryPacker.cpp in Sources */, 4BCE0051227CE8CA000CA200 /* Video.cpp in Sources */, + 4B0C956E22A7109A0015A8F6 /* PlusTooBIN.cpp in Sources */, 4B894536201967B4007DE474 /* Z80.cpp in Sources */, 4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */, 4BEA52661DF3472B007E74F2 /* TIASound.cpp in Sources */, @@ -4097,6 +4108,7 @@ 4B8334861F5DA3780097E338 /* 6502Storage.cpp in Sources */, 4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */, 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */, + 4B0C957122A74E880015A8F6 /* SonyDrive.cpp in Sources */, 4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */, 4B55DD8320DF06680043F2E5 /* MachinePicker.swift in Sources */, 4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */, diff --git a/Storage/Disk/DiskImage/Formats/PlusTooBIN.cpp b/Storage/Disk/DiskImage/Formats/PlusTooBIN.cpp new file mode 100644 index 000000000..d78a7582e --- /dev/null +++ b/Storage/Disk/DiskImage/Formats/PlusTooBIN.cpp @@ -0,0 +1,49 @@ +// +// PlusTooBIN.cpp +// Clock Signal +// +// Created by Thomas Harte on 04/06/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#include "PlusTooBIN.hpp" + +#include "../../Track/PCMTrack.hpp" +#include "../../Encodings/AppleGCR/Encoder.hpp" + +using namespace Storage::Disk; + +namespace { +const long sector_size = 1024; +} + +PlusTooBIN::PlusTooBIN(const std::string &file_name) : + file_(file_name) { + // BIN isn't really meant to be an emulator file format, it's primarily + // a convenience for the PlusToo Macintosh clone. So validation is + // fairly light. + if(file_.stats().st_size != 1638400) + throw Error::InvalidFormat; +} + +HeadPosition PlusTooBIN::get_maximum_head_position() { + return HeadPosition(80); +} + +int PlusTooBIN::get_head_count() { + return 2; +} + +std::shared_ptr PlusTooBIN::get_track_at_position(Track::Address address) { + if(address.position >= get_maximum_head_position()) return nullptr; + if(address.head >= get_head_count()) return nullptr; + + const auto start_position = Encodings::AppleGCR::Macintosh::sectors_in_track(address.position.as_int()); + const long file_offset = long(start_position.start * 2 + address.head * start_position.start) * sector_size; + file_.seek(file_offset, SEEK_SET); + + const auto track_contents = file_.read(std::size_t(sector_size * start_position.length)); + const std::size_t number_of_bits = std::size_t(sector_size * start_position.length * 8); + + return std::shared_ptr(new PCMTrack(PCMSegment(number_of_bits, track_contents))); +} diff --git a/Storage/Disk/DiskImage/Formats/PlusTooBIN.hpp b/Storage/Disk/DiskImage/Formats/PlusTooBIN.hpp new file mode 100644 index 000000000..de87d554e --- /dev/null +++ b/Storage/Disk/DiskImage/Formats/PlusTooBIN.hpp @@ -0,0 +1,40 @@ +// +// PlusTooBIN.hpp +// Clock Signal +// +// Created by Thomas Harte on 04/06/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#ifndef PlusTooBIN_hpp +#define PlusTooBIN_hpp + +#include "../DiskImage.hpp" +#include "../../../FileHolder.hpp" + +#include + +namespace Storage { +namespace Disk { + +/*! + Provides a @c DiskImage capturing the raw bitstream contained in a PlusToo-style BIN file. +*/ +class PlusTooBIN: public DiskImage { + public: + PlusTooBIN(const std::string &file_name); + + // Implemented to satisfy @c DiskImage. + HeadPosition get_maximum_head_position() override; + int get_head_count() override; + std::shared_ptr get_track_at_position(Track::Address address) override; + + private: + Storage::FileHolder file_; +}; + +} +} + + +#endif /* PlusTooBIN_hpp */