diff --git a/Components/DiskII/DiskII.cpp b/Components/DiskII/DiskII.cpp index f2f78ac4e..21f3daf7c 100644 --- a/Components/DiskII/DiskII.cpp +++ b/Components/DiskII/DiskII.cpp @@ -22,7 +22,7 @@ namespace { DiskII::DiskII(int clock_rate) : clock_rate_(clock_rate), inputs_(input_command), - drives_{{static_cast(clock_rate), 300, 1}, {static_cast(clock_rate), 300, 1}} + drives_{{clock_rate, 300, 1}, {clock_rate, 300, 1}} { drives_[0].set_clocking_hint_observer(this); drives_[1].set_clocking_hint_observer(this); diff --git a/Components/DiskII/IWM.hpp b/Components/DiskII/IWM.hpp index d409b6b00..cdc52e957 100644 --- a/Components/DiskII/IWM.hpp +++ b/Components/DiskII/IWM.hpp @@ -16,6 +16,30 @@ namespace Apple { +/*! + Defines the drive interface used by the IWM, derived from the external pinout as + per e.g. https://old.pinouts.ru/HD/MacExtDrive_pinout.shtml + + These are subclassed of Storage::Disk::Drive, so accept any disk the emulator supports, + and provide the usual read/write interface for on-disk data. +*/ +struct IWMDrive: public Storage::Disk::Drive { + IWMDrive(int input_clock_rate, int number_of_heads) : Storage::Disk::Drive(input_clock_rate, number_of_heads) {} + + enum Line: int { + CA0 = 1 << 0, + CA1 = 1 << 1, + CA2 = 1 << 2, + LSTRB = 1 << 3, + SEL = 1 << 4, + }; + + virtual void set_enabled(bool) = 0; + virtual void set_control_lines(int) = 0; + virtual bool read() = 0; + virtual void write(bool value) = 0; +}; + class IWM: public Storage::Disk::Drive::EventDelegate { public: diff --git a/Components/DiskII/MacintoshDoubleDensityDrive.cpp b/Components/DiskII/MacintoshDoubleDensityDrive.cpp new file mode 100644 index 000000000..5301bd9e2 --- /dev/null +++ b/Components/DiskII/MacintoshDoubleDensityDrive.cpp @@ -0,0 +1,55 @@ +// +// MacintoshDoubleDensityDrive.cpp +// Clock Signal +// +// Created by Thomas Harte on 10/07/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#include "MacintoshDoubleDensityDrive.hpp" + +using namespace Apple::Macintosh; + +DoubleDensityDrive::DoubleDensityDrive(int input_clock_rate, bool is_800k) : + IWMDrive(input_clock_rate, is_800k ? 2 : 1), // Only 800kb drives are double sided. + is_800k_(is_800k) { + // Start with a valid rotation speed. + if(is_800k) { + set_rotation_speed(393.3807f); + } +} + +// MARK: - Control input/output. + +void DoubleDensityDrive::set_enabled(bool) { +} + +void DoubleDensityDrive::set_control_lines(int lines) { +} + +bool DoubleDensityDrive::read() { + return false; +} + +void DoubleDensityDrive::write(bool value) { +} + +// MARK: - Speed Selection + +void DoubleDensityDrive::did_step(Storage::Disk::HeadPosition to_position) { + // The 800kb drive automatically selects rotation speed as a function of + // head position; the 400kb drive doesn't do so. + if(is_800k_) { + /* + Numbers below cribbed from the Kryoflux forums. + */ + const int zone = to_position.as_int() >> 4; + switch(zone) { + case 0: set_rotation_speed(393.3807f); break; + case 1: set_rotation_speed(429.1723f); break; + case 2: set_rotation_speed(472.1435f); break; + case 3: set_rotation_speed(524.5672f); break; + default: set_rotation_speed(590.1098f); break; + } + } +} diff --git a/Components/DiskII/MacintoshDoubleDensityDrive.hpp b/Components/DiskII/MacintoshDoubleDensityDrive.hpp new file mode 100644 index 000000000..cc4f7f1cb --- /dev/null +++ b/Components/DiskII/MacintoshDoubleDensityDrive.hpp @@ -0,0 +1,36 @@ +// +// MacintoshDoubleDensityDrive.hpp +// Clock Signal +// +// Created by Thomas Harte on 10/07/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#ifndef MacintoshDoubleDensityDrive_hpp +#define MacintoshDoubleDensityDrive_hpp + +#include "IWM.hpp" + +namespace Apple { +namespace Macintosh { + +class DoubleDensityDrive: public IWMDrive { + public: + DoubleDensityDrive(int input_clock_rate, bool is_800k); + + void set_enabled(bool) override; + void set_control_lines(int) override; + bool read() override; + void write(bool value) override; + + private: + // To receive the proper notifications from Storage::Disk::Drive. + void did_step(Storage::Disk::HeadPosition to_position) override; + + bool is_800k_; +}; + +} +} + +#endif /* MacintoshDoubleDensityDrive_hpp */ diff --git a/Machines/Apple/Macintosh/SonyDrive.cpp b/Machines/Apple/Macintosh/SonyDrive.cpp index 90a7c245e..28fef911d 100644 --- a/Machines/Apple/Macintosh/SonyDrive.cpp +++ b/Machines/Apple/Macintosh/SonyDrive.cpp @@ -11,7 +11,7 @@ using namespace Apple::Macintosh; SonyDrive::SonyDrive(int input_clock_rate, bool is_800k) : - Storage::Disk::Drive(static_cast(input_clock_rate), is_800k ? 2 : 1), is_800k_(is_800k) { + Storage::Disk::Drive(input_clock_rate, is_800k ? 2 : 1), is_800k_(is_800k) { // Start with a valid rotation speed. if(is_800k) { set_rotation_speed(393.3807f); diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 71fb17477..7748daaeb 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -639,6 +639,8 @@ 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; }; 4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */; }; 4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCA6CC61D9DD9F000C2D7B2 /* CommodoreROM.cpp */; }; + 4BCD634922D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCD634722D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp */; }; + 4BCD634A22D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCD634722D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp */; }; 4BCE0051227CE8CA000CA200 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE004D227CE8CA000CA200 /* Video.cpp */; }; 4BCE0052227CE8CA000CA200 /* DiskIICard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE004E227CE8CA000CA200 /* DiskIICard.cpp */; }; 4BCE0053227CE8CA000CA200 /* AppleII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE0050227CE8CA000CA200 /* AppleII.cpp */; }; @@ -1430,6 +1432,8 @@ 4BCA6CC61D9DD9F000C2D7B2 /* CommodoreROM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommodoreROM.cpp; path = Encodings/CommodoreROM.cpp; sourceTree = ""; }; 4BCA6CC71D9DD9F000C2D7B2 /* CommodoreROM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CommodoreROM.hpp; path = Encodings/CommodoreROM.hpp; sourceTree = ""; }; 4BCA98C21D065CA20062F44C /* 6522.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6522.hpp; sourceTree = ""; }; + 4BCD634722D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MacintoshDoubleDensityDrive.cpp; sourceTree = ""; }; + 4BCD634822D6756400F567F1 /* MacintoshDoubleDensityDrive.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MacintoshDoubleDensityDrive.hpp; sourceTree = ""; }; 4BCE004A227CE8CA000CA200 /* AppleII.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AppleII.hpp; sourceTree = ""; }; 4BCE004B227CE8CA000CA200 /* Card.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Card.hpp; sourceTree = ""; }; 4BCE004C227CE8CA000CA200 /* DiskIICard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskIICard.hpp; sourceTree = ""; }; @@ -1823,6 +1827,8 @@ 4B302183208A550100773308 /* DiskII.cpp */, 4BEE1498227FC0EA00133682 /* IWM.cpp */, 4BEE1499227FC0EA00133682 /* IWM.hpp */, + 4BCD634722D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp */, + 4BCD634822D6756400F567F1 /* MacintoshDoubleDensityDrive.hpp */, ); path = DiskII; sourceTree = ""; @@ -3900,6 +3906,7 @@ 4B055A9D1FAE85DA0060FFFF /* D64.cpp in Sources */, 4B055ABB1FAE86170060FFFF /* Oric.cpp in Sources */, 4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */, + 4BCD634A22D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */, 4B05401F219D1618001BF69C /* ScanTarget.cpp in Sources */, 4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */, 4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */, @@ -4121,6 +4128,7 @@ 4B8334841F5DA0360097E338 /* Z80Storage.cpp in Sources */, 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */, 4BD191F42191180E0042E144 /* ScanTarget.cpp in Sources */, + 4BCD634922D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */, 4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */, 4B89452A201967B4007DE474 /* File.cpp in Sources */, 4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */, diff --git a/Storage/Disk/Controller/DiskController.cpp b/Storage/Disk/Controller/DiskController.cpp index ea4b3c056..547f01812 100644 --- a/Storage/Disk/Controller/DiskController.cpp +++ b/Storage/Disk/Controller/DiskController.cpp @@ -15,7 +15,7 @@ using namespace Storage::Disk; Controller::Controller(Cycles clock_rate) : clock_rate_multiplier_(128000000 / clock_rate.as_int()), clock_rate_(clock_rate.as_int() * clock_rate_multiplier_), - empty_drive_(new Drive(static_cast(clock_rate.as_int()), 1, 1)) { + empty_drive_(new Drive(clock_rate.as_int(), 1, 1)) { // seed this class with a PLL, any PLL, so that it's safe to assume non-nullptr later Time one(1); set_expected_bit_length(one); diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 846c15714..82e332291 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -18,7 +18,7 @@ using namespace Storage::Disk; -Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads): +Drive::Drive(int input_clock_rate, int revolutions_per_minute, int number_of_heads): Storage::TimedEventLoop(input_clock_rate), rotational_multiplier_(60.0f / float(revolutions_per_minute)), available_heads_(number_of_heads) { @@ -35,7 +35,7 @@ Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int numb } } -Drive::Drive(unsigned int input_clock_rate, int number_of_heads) : Drive(input_clock_rate, 300, number_of_heads) {} +Drive::Drive(int input_clock_rate, int number_of_heads) : Drive(input_clock_rate, 300, number_of_heads) {} void Drive::set_rotation_speed(float revolutions_per_minute) { // TODO: probably I should look into @@ -166,7 +166,7 @@ void Drive::set_event_delegate(Storage::Disk::Drive::EventDelegate *delegate) { } void Drive::advance(const Cycles cycles) { - cycles_since_index_hole_ += static_cast(cycles.as_int()); + cycles_since_index_hole_ += cycles.as_int(); if(event_delegate_) event_delegate_->advance(cycles); } diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index 62baeb042..2c0eb0f57 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -24,8 +24,8 @@ namespace Disk { class Drive: public ClockingHint::Source, public TimedEventLoop { public: - Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads); - Drive(unsigned int input_clock_rate, int number_of_heads); + Drive(int input_clock_rate, int revolutions_per_minute, int number_of_heads); + Drive(int input_clock_rate, int number_of_heads); ~Drive(); /*! diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index 72ece532d..a3d8c2f27 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -13,7 +13,7 @@ using namespace Storage::Tape; // MARK: - Lifecycle -TapePlayer::TapePlayer(unsigned int input_clock_rate) : +TapePlayer::TapePlayer(int input_clock_rate) : TimedEventLoop(input_clock_rate) {} @@ -115,7 +115,7 @@ void TapePlayer::process_next_event() { // MARK: - Binary Player -BinaryTapePlayer::BinaryTapePlayer(unsigned int input_clock_rate) : +BinaryTapePlayer::BinaryTapePlayer(int input_clock_rate) : TapePlayer(input_clock_rate) {} diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 329da3e3b..47b7bbd1d 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -97,7 +97,7 @@ class Tape { */ class TapePlayer: public TimedEventLoop, public ClockingHint::Source { public: - TapePlayer(unsigned int input_clock_rate); + TapePlayer(int input_clock_rate); void set_tape(std::shared_ptr tape); bool has_tape(); @@ -130,7 +130,7 @@ class TapePlayer: public TimedEventLoop, public ClockingHint::Source { */ class BinaryTapePlayer: public TapePlayer { public: - BinaryTapePlayer(unsigned int input_clock_rate); + BinaryTapePlayer(int input_clock_rate); void set_motor_control(bool enabled); bool get_motor_control() const; diff --git a/Storage/TimedEventLoop.cpp b/Storage/TimedEventLoop.cpp index 5541bf935..92f005406 100644 --- a/Storage/TimedEventLoop.cpp +++ b/Storage/TimedEventLoop.cpp @@ -15,7 +15,7 @@ using namespace Storage; -TimedEventLoop::TimedEventLoop(unsigned int input_clock_rate) : +TimedEventLoop::TimedEventLoop(int input_clock_rate) : input_clock_rate_(input_clock_rate) {} void TimedEventLoop::run_for(const Cycles cycles) { @@ -46,11 +46,11 @@ void TimedEventLoop::run_for(const Cycles cycles) { assert(cycles_until_event_ > 0); } -unsigned int TimedEventLoop::get_cycles_until_next_event() { - return static_cast(std::max(cycles_until_event_, 0)); +int TimedEventLoop::get_cycles_until_next_event() { + return std::max(cycles_until_event_, 0); } -unsigned int TimedEventLoop::get_input_clock_rate() { +int TimedEventLoop::get_input_clock_rate() { return input_clock_rate_; } diff --git a/Storage/TimedEventLoop.hpp b/Storage/TimedEventLoop.hpp index c3bd7ec75..367f2dc43 100644 --- a/Storage/TimedEventLoop.hpp +++ b/Storage/TimedEventLoop.hpp @@ -42,7 +42,7 @@ namespace Storage { /*! Constructs a timed event loop that will be clocked at @c input_clock_rate. */ - TimedEventLoop(unsigned int input_clock_rate); + TimedEventLoop(int input_clock_rate); /*! Advances the event loop by @c number_of_cycles cycles. @@ -52,12 +52,12 @@ namespace Storage { /*! @returns the number of whole cycles remaining until the next event is triggered. */ - unsigned int get_cycles_until_next_event(); + int get_cycles_until_next_event(); /*! @returns the input clock rate. */ - unsigned int get_input_clock_rate(); + int get_input_clock_rate(); protected: /*! @@ -101,7 +101,7 @@ namespace Storage { Time get_time_into_next_event(); private: - unsigned int input_clock_rate_ = 0; + int input_clock_rate_ = 0; int cycles_until_event_ = 0; float subcycles_until_event_ = 0.0; };