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:
parent
886946cc8c
commit
c4ab0bb867
@ -22,7 +22,7 @@ namespace {
|
||||
DiskII::DiskII(int clock_rate) :
|
||||
clock_rate_(clock_rate),
|
||||
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_[1].set_clocking_hint_observer(this);
|
||||
|
@ -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:
|
||||
|
55
Components/DiskII/MacintoshDoubleDensityDrive.cpp
Normal file
55
Components/DiskII/MacintoshDoubleDensityDrive.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
36
Components/DiskII/MacintoshDoubleDensityDrive.hpp
Normal file
36
Components/DiskII/MacintoshDoubleDensityDrive.hpp
Normal 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 */
|
@ -11,7 +11,7 @@
|
||||
using namespace Apple::Macintosh;
|
||||
|
||||
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.
|
||||
if(is_800k) {
|
||||
set_rotation_speed(393.3807f);
|
||||
|
@ -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 = "<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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1823,6 +1827,8 @@
|
||||
4B302183208A550100773308 /* DiskII.cpp */,
|
||||
4BEE1498227FC0EA00133682 /* IWM.cpp */,
|
||||
4BEE1499227FC0EA00133682 /* IWM.hpp */,
|
||||
4BCD634722D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp */,
|
||||
4BCD634822D6756400F567F1 /* MacintoshDoubleDensityDrive.hpp */,
|
||||
);
|
||||
path = DiskII;
|
||||
sourceTree = "<group>";
|
||||
@ -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 */,
|
||||
|
@ -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<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
|
||||
Time one(1);
|
||||
set_expected_bit_length(one);
|
||||
|
@ -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<unsigned int>(cycles.as_int());
|
||||
cycles_since_index_hole_ += cycles.as_int();
|
||||
if(event_delegate_) event_delegate_->advance(cycles);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
/*!
|
||||
|
@ -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)
|
||||
{}
|
||||
|
||||
|
@ -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<Storage::Tape::Tape> 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;
|
||||
|
||||
|
@ -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<unsigned int>(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_;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user