2016-07-15 10:51:11 +00:00
|
|
|
//
|
2016-09-26 00:05:56 +00:00
|
|
|
// DiskController.cpp
|
2016-07-15 10:51:11 +00:00
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 14/07/2016.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2016 Thomas Harte. All rights reserved.
|
2016-07-15 10:51:11 +00:00
|
|
|
//
|
|
|
|
|
2016-09-26 00:05:56 +00:00
|
|
|
#include "DiskController.hpp"
|
2017-09-10 23:23:23 +00:00
|
|
|
|
2016-08-27 21:18:12 +00:00
|
|
|
using namespace Storage::Disk;
|
2016-07-15 12:28:34 +00:00
|
|
|
|
2017-09-11 02:56:05 +00:00
|
|
|
Controller::Controller(Cycles clock_rate) :
|
2019-10-30 02:36:29 +00:00
|
|
|
clock_rate_multiplier_(128000000 / clock_rate.as_integral()),
|
|
|
|
clock_rate_(clock_rate.as_integral() * clock_rate_multiplier_),
|
2020-01-12 22:45:02 +00:00
|
|
|
pll_(100, *this),
|
2020-02-12 02:59:13 +00:00
|
|
|
empty_drive_(int(clock_rate.as_integral()), 1, 1),
|
|
|
|
drive_(&empty_drive_) {
|
2020-02-13 03:28:42 +00:00
|
|
|
empty_drive_.set_clocking_hint_observer(this);
|
2020-01-12 22:25:21 +00:00
|
|
|
set_expected_bit_length(Time(1));
|
2016-07-29 09:19:01 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 04:37:06 +00:00
|
|
|
void Controller::set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) {
|
2018-05-28 03:17:06 +00:00
|
|
|
update_clocking_observer();
|
2017-08-20 15:54:54 +00:00
|
|
|
}
|
|
|
|
|
2020-05-10 01:22:51 +00:00
|
|
|
ClockingHint::Preference Controller::preferred_clocking() const {
|
2020-02-13 03:28:42 +00:00
|
|
|
// Nominate RealTime clocking if any drive currently wants any clocking whatsoever.
|
|
|
|
// Otherwise, ::None will do.
|
|
|
|
for(auto &drive: drives_) {
|
2021-10-14 19:37:55 +00:00
|
|
|
const auto preferred_clocking = drive->preferred_clocking();
|
2021-10-06 20:40:48 +00:00
|
|
|
if(preferred_clocking != ClockingHint::Preference::None) {
|
2020-02-13 03:28:42 +00:00
|
|
|
return ClockingHint::Preference::RealTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(empty_drive_.preferred_clocking() != ClockingHint::Preference::None) {
|
|
|
|
return ClockingHint::Preference::RealTime;
|
|
|
|
}
|
|
|
|
return ClockingHint::Preference::None;
|
2017-08-20 15:54:54 +00:00
|
|
|
}
|
|
|
|
|
2017-07-28 02:05:29 +00:00
|
|
|
void Controller::run_for(const Cycles cycles) {
|
2020-02-13 03:28:42 +00:00
|
|
|
for(auto &drive: drives_) {
|
2021-10-14 19:37:55 +00:00
|
|
|
drive->run_for(cycles);
|
2020-02-13 03:28:42 +00:00
|
|
|
}
|
|
|
|
empty_drive_.run_for(cycles);
|
2016-07-29 11:31:02 +00:00
|
|
|
}
|
|
|
|
|
2017-09-10 23:23:23 +00:00
|
|
|
Drive &Controller::get_drive() {
|
2020-02-12 02:59:13 +00:00
|
|
|
return *drive_;
|
2016-12-24 18:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-11-12 20:59:11 +00:00
|
|
|
// MARK: - Drive::EventDelegate
|
2016-12-24 18:07:23 +00:00
|
|
|
|
2019-07-02 19:43:03 +00:00
|
|
|
void Controller::process_event(const Drive::Event &event) {
|
2017-09-10 23:23:23 +00:00
|
|
|
switch(event.type) {
|
2020-01-12 22:25:21 +00:00
|
|
|
case Track::Event::FluxTransition: pll_.add_pulse(); break;
|
2017-09-10 23:23:23 +00:00
|
|
|
case Track::Event::IndexHole: process_index_hole(); break;
|
|
|
|
}
|
2016-12-24 18:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-09-10 23:23:23 +00:00
|
|
|
void Controller::advance(const Cycles cycles) {
|
2020-01-12 22:25:21 +00:00
|
|
|
if(is_reading_) pll_.run_for(Cycles(cycles.as_integral() * clock_rate_multiplier_));
|
2016-12-24 18:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-09-10 23:23:23 +00:00
|
|
|
void Controller::process_write_completed() {
|
|
|
|
// Provided for subclasses to override.
|
2016-12-24 18:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-11-12 20:59:11 +00:00
|
|
|
// MARK: - PLL control and delegate
|
2016-09-26 01:24:16 +00:00
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
void Controller::set_expected_bit_length(Time bit_length) {
|
2016-12-03 16:59:28 +00:00
|
|
|
bit_length_ = bit_length;
|
2016-12-25 17:32:25 +00:00
|
|
|
bit_length_.simplify();
|
2016-09-26 01:24:16 +00:00
|
|
|
|
2019-10-30 02:36:29 +00:00
|
|
|
Time cycles_per_bit = Storage::Time(int(clock_rate_)) * bit_length;
|
2017-09-10 23:23:23 +00:00
|
|
|
cycles_per_bit.simplify();
|
2016-12-25 17:31:38 +00:00
|
|
|
|
2016-09-26 01:24:16 +00:00
|
|
|
// this conversion doesn't need to be exact because there's a lot of variation to be taken
|
|
|
|
// account of in rotation speed, air turbulence, etc, so a direct conversion will do
|
2020-01-12 22:25:21 +00:00
|
|
|
const int clocks_per_bit = cycles_per_bit.get<int>();
|
|
|
|
pll_.set_clocks_per_bit(clocks_per_bit);
|
2016-09-26 01:24:16 +00:00
|
|
|
}
|
2016-07-29 11:31:02 +00:00
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
void Controller::digital_phase_locked_loop_output_bit(int value) {
|
2017-09-15 02:30:40 +00:00
|
|
|
if(is_reading_) process_input_bit(value);
|
2016-12-01 03:26:02 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 02:59:13 +00:00
|
|
|
void Controller::set_drive(int index_mask) {
|
|
|
|
if(drive_selection_mask_ == index_mask) {
|
|
|
|
return;
|
|
|
|
}
|
2017-09-10 23:23:23 +00:00
|
|
|
|
2020-07-30 01:06:41 +00:00
|
|
|
const ClockingHint::Preference former_preference = preferred_clocking();
|
2020-02-12 02:59:13 +00:00
|
|
|
|
2020-02-13 03:28:42 +00:00
|
|
|
// Stop receiving events from the current drive.
|
2020-02-12 02:59:13 +00:00
|
|
|
get_drive().set_event_delegate(nullptr);
|
2020-02-13 03:28:42 +00:00
|
|
|
|
|
|
|
// TODO: a transfer of writing state, if writing?
|
2016-09-26 01:24:16 +00:00
|
|
|
|
2020-02-12 02:59:13 +00:00
|
|
|
if(!index_mask) {
|
|
|
|
drive_ = &empty_drive_;
|
|
|
|
} else {
|
2020-02-13 03:28:42 +00:00
|
|
|
// TEMPORARY FIX: connect up only the first selected drive.
|
|
|
|
// TODO: at least merge events if multiple drives are selected. Some computers have
|
|
|
|
// controllers that allow this, with usually meaningless results as far as I can
|
|
|
|
// imagine. But the limit of an emulator shouldn't be the author's imagination.
|
2020-02-12 02:59:13 +00:00
|
|
|
size_t index = 0;
|
|
|
|
while(!(index_mask&1)) {
|
|
|
|
index_mask >>= 1;
|
|
|
|
++index;
|
2017-09-10 23:23:23 +00:00
|
|
|
}
|
2021-10-14 19:37:55 +00:00
|
|
|
drive_ = drives_[index].get();
|
2020-02-12 02:59:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get_drive().set_event_delegate(this);
|
|
|
|
|
2020-07-30 01:06:41 +00:00
|
|
|
if(preferred_clocking() != former_preference) {
|
2020-02-12 02:59:13 +00:00
|
|
|
update_clocking_observer();
|
2016-12-26 00:19:22 +00:00
|
|
|
}
|
2016-09-26 01:24:16 +00:00
|
|
|
}
|
2016-12-25 17:31:38 +00:00
|
|
|
|
2017-09-10 23:23:23 +00:00
|
|
|
void Controller::begin_writing(bool clamp_to_index_hole) {
|
2017-09-15 02:30:40 +00:00
|
|
|
is_reading_ = false;
|
2017-09-10 23:23:23 +00:00
|
|
|
get_drive().begin_writing(bit_length_, clamp_to_index_hole);
|
|
|
|
}
|
2017-09-15 02:30:40 +00:00
|
|
|
|
|
|
|
void Controller::end_writing() {
|
2017-09-16 21:07:36 +00:00
|
|
|
if(!is_reading_) {
|
|
|
|
is_reading_ = true;
|
|
|
|
get_drive().end_writing();
|
|
|
|
}
|
2017-09-15 02:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Controller::is_reading() {
|
|
|
|
return is_reading_;
|
|
|
|
}
|