1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Starts sketching out an interface for IWM drives, eliminating a dangling use of unsigned as it goes.

This commit is contained in:
Thomas Harte 2019-07-10 16:05:59 -04:00
parent 886946cc8c
commit c4ab0bb867
13 changed files with 143 additions and 20 deletions

View File

@ -22,7 +22,7 @@ namespace {
DiskII::DiskII(int clock_rate) : DiskII::DiskII(int clock_rate) :
clock_rate_(clock_rate), clock_rate_(clock_rate),
inputs_(input_command), inputs_(input_command),
drives_{{static_cast<unsigned int>(clock_rate), 300, 1}, {static_cast<unsigned int>(clock_rate), 300, 1}} drives_{{clock_rate, 300, 1}, {clock_rate, 300, 1}}
{ {
drives_[0].set_clocking_hint_observer(this); drives_[0].set_clocking_hint_observer(this);
drives_[1].set_clocking_hint_observer(this); drives_[1].set_clocking_hint_observer(this);

View File

@ -16,6 +16,30 @@
namespace Apple { 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: class IWM:
public Storage::Disk::Drive::EventDelegate { public Storage::Disk::Drive::EventDelegate {
public: public:

View File

@ -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;
}
}
}

View File

@ -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 */

View File

@ -11,7 +11,7 @@
using namespace Apple::Macintosh; using namespace Apple::Macintosh;
SonyDrive::SonyDrive(int input_clock_rate, bool is_800k) : SonyDrive::SonyDrive(int input_clock_rate, bool is_800k) :
Storage::Disk::Drive(static_cast<unsigned int>(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. // Start with a valid rotation speed.
if(is_800k) { if(is_800k) {
set_rotation_speed(393.3807f); set_rotation_speed(393.3807f);

View File

@ -639,6 +639,8 @@
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; }; 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; };
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */; }; 4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */; };
4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCA6CC61D9DD9F000C2D7B2 /* CommodoreROM.cpp */; }; 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 */; }; 4BCE0051227CE8CA000CA200 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE004D227CE8CA000CA200 /* Video.cpp */; };
4BCE0052227CE8CA000CA200 /* DiskIICard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE004E227CE8CA000CA200 /* DiskIICard.cpp */; }; 4BCE0052227CE8CA000CA200 /* DiskIICard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE004E227CE8CA000CA200 /* DiskIICard.cpp */; };
4BCE0053227CE8CA000CA200 /* AppleII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE0050227CE8CA000CA200 /* AppleII.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 = "<group>"; }; 4BCA6CC61D9DD9F000C2D7B2 /* CommodoreROM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommodoreROM.cpp; path = Encodings/CommodoreROM.cpp; sourceTree = "<group>"; };
4BCA6CC71D9DD9F000C2D7B2 /* CommodoreROM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CommodoreROM.hpp; path = Encodings/CommodoreROM.hpp; sourceTree = "<group>"; }; 4BCA6CC71D9DD9F000C2D7B2 /* CommodoreROM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CommodoreROM.hpp; path = Encodings/CommodoreROM.hpp; sourceTree = "<group>"; };
4BCA98C21D065CA20062F44C /* 6522.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6522.hpp; sourceTree = "<group>"; }; 4BCA98C21D065CA20062F44C /* 6522.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6522.hpp; sourceTree = "<group>"; };
4BCD634722D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MacintoshDoubleDensityDrive.cpp; sourceTree = "<group>"; };
4BCD634822D6756400F567F1 /* MacintoshDoubleDensityDrive.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MacintoshDoubleDensityDrive.hpp; sourceTree = "<group>"; };
4BCE004A227CE8CA000CA200 /* AppleII.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AppleII.hpp; sourceTree = "<group>"; }; 4BCE004A227CE8CA000CA200 /* AppleII.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AppleII.hpp; sourceTree = "<group>"; };
4BCE004B227CE8CA000CA200 /* Card.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Card.hpp; sourceTree = "<group>"; }; 4BCE004B227CE8CA000CA200 /* Card.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Card.hpp; sourceTree = "<group>"; };
4BCE004C227CE8CA000CA200 /* DiskIICard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskIICard.hpp; sourceTree = "<group>"; }; 4BCE004C227CE8CA000CA200 /* DiskIICard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskIICard.hpp; sourceTree = "<group>"; };
@ -1823,6 +1827,8 @@
4B302183208A550100773308 /* DiskII.cpp */, 4B302183208A550100773308 /* DiskII.cpp */,
4BEE1498227FC0EA00133682 /* IWM.cpp */, 4BEE1498227FC0EA00133682 /* IWM.cpp */,
4BEE1499227FC0EA00133682 /* IWM.hpp */, 4BEE1499227FC0EA00133682 /* IWM.hpp */,
4BCD634722D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp */,
4BCD634822D6756400F567F1 /* MacintoshDoubleDensityDrive.hpp */,
); );
path = DiskII; path = DiskII;
sourceTree = "<group>"; sourceTree = "<group>";
@ -3900,6 +3906,7 @@
4B055A9D1FAE85DA0060FFFF /* D64.cpp in Sources */, 4B055A9D1FAE85DA0060FFFF /* D64.cpp in Sources */,
4B055ABB1FAE86170060FFFF /* Oric.cpp in Sources */, 4B055ABB1FAE86170060FFFF /* Oric.cpp in Sources */,
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */, 4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */,
4BCD634A22D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */,
4B05401F219D1618001BF69C /* ScanTarget.cpp in Sources */, 4B05401F219D1618001BF69C /* ScanTarget.cpp in Sources */,
4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */, 4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */,
4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */, 4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */,
@ -4121,6 +4128,7 @@
4B8334841F5DA0360097E338 /* Z80Storage.cpp in Sources */, 4B8334841F5DA0360097E338 /* Z80Storage.cpp in Sources */,
4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */, 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */,
4BD191F42191180E0042E144 /* ScanTarget.cpp in Sources */, 4BD191F42191180E0042E144 /* ScanTarget.cpp in Sources */,
4BCD634922D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */,
4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */, 4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */,
4B89452A201967B4007DE474 /* File.cpp in Sources */, 4B89452A201967B4007DE474 /* File.cpp in Sources */,
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */, 4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */,

View File

@ -15,7 +15,7 @@ using namespace Storage::Disk;
Controller::Controller(Cycles clock_rate) : Controller::Controller(Cycles clock_rate) :
clock_rate_multiplier_(128000000 / clock_rate.as_int()), clock_rate_multiplier_(128000000 / clock_rate.as_int()),
clock_rate_(clock_rate.as_int() * clock_rate_multiplier_), clock_rate_(clock_rate.as_int() * clock_rate_multiplier_),
empty_drive_(new Drive(static_cast<unsigned int>(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 // seed this class with a PLL, any PLL, so that it's safe to assume non-nullptr later
Time one(1); Time one(1);
set_expected_bit_length(one); set_expected_bit_length(one);

View File

@ -18,7 +18,7 @@
using namespace Storage::Disk; 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), Storage::TimedEventLoop(input_clock_rate),
rotational_multiplier_(60.0f / float(revolutions_per_minute)), rotational_multiplier_(60.0f / float(revolutions_per_minute)),
available_heads_(number_of_heads) { 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) { void Drive::set_rotation_speed(float revolutions_per_minute) {
// TODO: probably I should look into // 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) { void Drive::advance(const Cycles cycles) {
cycles_since_index_hole_ += static_cast<unsigned int>(cycles.as_int()); cycles_since_index_hole_ += cycles.as_int();
if(event_delegate_) event_delegate_->advance(cycles); if(event_delegate_) event_delegate_->advance(cycles);
} }

View File

@ -24,8 +24,8 @@ namespace Disk {
class Drive: public ClockingHint::Source, public TimedEventLoop { class Drive: public ClockingHint::Source, public TimedEventLoop {
public: public:
Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads); Drive(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 number_of_heads);
~Drive(); ~Drive();
/*! /*!

View File

@ -13,7 +13,7 @@ using namespace Storage::Tape;
// MARK: - Lifecycle // MARK: - Lifecycle
TapePlayer::TapePlayer(unsigned int input_clock_rate) : TapePlayer::TapePlayer(int input_clock_rate) :
TimedEventLoop(input_clock_rate) TimedEventLoop(input_clock_rate)
{} {}
@ -115,7 +115,7 @@ void TapePlayer::process_next_event() {
// MARK: - Binary Player // MARK: - Binary Player
BinaryTapePlayer::BinaryTapePlayer(unsigned int input_clock_rate) : BinaryTapePlayer::BinaryTapePlayer(int input_clock_rate) :
TapePlayer(input_clock_rate) TapePlayer(input_clock_rate)
{} {}

View File

@ -97,7 +97,7 @@ class Tape {
*/ */
class TapePlayer: public TimedEventLoop, public ClockingHint::Source { class TapePlayer: public TimedEventLoop, public ClockingHint::Source {
public: public:
TapePlayer(unsigned int input_clock_rate); TapePlayer(int input_clock_rate);
void set_tape(std::shared_ptr<Storage::Tape::Tape> tape); void set_tape(std::shared_ptr<Storage::Tape::Tape> tape);
bool has_tape(); bool has_tape();
@ -130,7 +130,7 @@ class TapePlayer: public TimedEventLoop, public ClockingHint::Source {
*/ */
class BinaryTapePlayer: public TapePlayer { class BinaryTapePlayer: public TapePlayer {
public: public:
BinaryTapePlayer(unsigned int input_clock_rate); BinaryTapePlayer(int input_clock_rate);
void set_motor_control(bool enabled); void set_motor_control(bool enabled);
bool get_motor_control() const; bool get_motor_control() const;

View File

@ -15,7 +15,7 @@
using namespace Storage; using namespace Storage;
TimedEventLoop::TimedEventLoop(unsigned int input_clock_rate) : TimedEventLoop::TimedEventLoop(int input_clock_rate) :
input_clock_rate_(input_clock_rate) {} input_clock_rate_(input_clock_rate) {}
void TimedEventLoop::run_for(const Cycles cycles) { void TimedEventLoop::run_for(const Cycles cycles) {
@ -46,11 +46,11 @@ void TimedEventLoop::run_for(const Cycles cycles) {
assert(cycles_until_event_ > 0); assert(cycles_until_event_ > 0);
} }
unsigned int TimedEventLoop::get_cycles_until_next_event() { int TimedEventLoop::get_cycles_until_next_event() {
return static_cast<unsigned int>(std::max(cycles_until_event_, 0)); return std::max(cycles_until_event_, 0);
} }
unsigned int TimedEventLoop::get_input_clock_rate() { int TimedEventLoop::get_input_clock_rate() {
return input_clock_rate_; return input_clock_rate_;
} }

View File

@ -42,7 +42,7 @@ namespace Storage {
/*! /*!
Constructs a timed event loop that will be clocked at @c input_clock_rate. 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. 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. @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. @returns the input clock rate.
*/ */
unsigned int get_input_clock_rate(); int get_input_clock_rate();
protected: protected:
/*! /*!
@ -101,7 +101,7 @@ namespace Storage {
Time get_time_into_next_event(); Time get_time_into_next_event();
private: private:
unsigned int input_clock_rate_ = 0; int input_clock_rate_ = 0;
int cycles_until_event_ = 0; int cycles_until_event_ = 0;
float subcycles_until_event_ = 0.0; float subcycles_until_event_ = 0.0;
}; };