1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-06 13:31:55 +00:00

Merge pull request #749 from TomHarte/DiskIndicator

Moves ownership of drives inside Disk::Controller.
This commit is contained in:
Thomas Harte 2020-02-12 23:37:32 -05:00 committed by GitHub
commit 0c1c5a0ab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 207 additions and 150 deletions

View File

@ -19,12 +19,10 @@ using namespace Analyser::Static::Commodore;
class CommodoreGCRParser: public Storage::Disk::Controller {
public:
std::shared_ptr<Storage::Disk::Drive> drive;
CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
drive = std::make_shared<Storage::Disk::Drive>(4000000, 300, 2);
set_drive(drive);
drive->set_motor_on(true);
emplace_drive(4000000, 300, 2);
set_drive(1);
get_drive().set_motor_on(true);
}
struct Sector {
@ -61,6 +59,10 @@ class CommodoreGCRParser: public Storage::Disk::Controller {
return get_sector(sector);
}
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
get_drive().set_disk(disk);
}
private:
unsigned int shift_register_;
int index_count_;
@ -170,7 +172,7 @@ class CommodoreGCRParser: public Storage::Disk::Controller {
std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk) {
std::vector<File> files;
CommodoreGCRParser parser;
parser.drive->set_disk(disk);
parser.set_disk(disk);
// find any sector whatsoever to establish the current track
std::shared_ptr<CommodoreGCRParser::Sector> sector;

View File

@ -661,17 +661,15 @@ class KeyboardState: public GI::AY38910::PortHandler {
class FDC: public Intel::i8272::i8272 {
private:
Intel::i8272::BusHandler bus_handler_;
std::shared_ptr<Storage::Disk::Drive> drive_;
public:
FDC() :
i8272(bus_handler_, Cycles(8000000)),
drive_(new Storage::Disk::Drive(8000000, 300, 1)) {
set_drive(drive_);
FDC() : i8272(bus_handler_, Cycles(8000000)) {
emplace_drive(8000000, 300, 1);
set_drive(1);
}
void set_motor_on(bool on) {
drive_->set_motor_on(on);
get_drive().set_motor_on(on);
}
void select_drive(int c) {
@ -679,11 +677,11 @@ class FDC: public Intel::i8272::i8272 {
}
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
drive_->set_disk(disk);
get_drive().set_disk(disk);
}
void set_activity_observer(Activity::Observer *observer) {
drive_->set_activity_observer(observer, "Drive 1", true);
get_drive().set_activity_observer(observer, "Drive 1", true);
}
};

View File

@ -441,7 +441,8 @@ class ConcreteMachine:
// Advance the relevant counters.
cycles_since_audio_update_ += length;
mfp_ += length;
dma_ += length;
if(dma_clocking_preference_ != ClockingHint::Preference::None)
dma_ += length;
keyboard_acia_ += length;
midi_acia_ += length;
bus_phase_ += length;
@ -462,7 +463,7 @@ class ConcreteMachine:
mfp_.flush();
}
if(dma_is_realtime_) {
if(dma_clocking_preference_ == ClockingHint::Preference::RealTime) {
dma_.flush();
}
@ -531,7 +532,7 @@ class ConcreteMachine:
bool may_defer_acias_ = true;
bool keyboard_needs_clock_ = false;
bool mfp_is_realtime_ = false;
bool dma_is_realtime_ = false;
ClockingHint::Preference dma_clocking_preference_ = ClockingHint::Preference::None;
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final {
// This is being called by one of the components; avoid any time flushing here as that's
// already dealt with (and, just to be absolutely sure, to avoid recursive mania).
@ -540,7 +541,7 @@ class ConcreteMachine:
(midi_acia_.last_valid()->preferred_clocking() != ClockingHint::Preference::RealTime);
keyboard_needs_clock_ = ikbd_.preferred_clocking() != ClockingHint::Preference::None;
mfp_is_realtime_ = mfp_.last_valid()->preferred_clocking() == ClockingHint::Preference::RealTime;
dma_is_realtime_ = dma_.last_valid()->preferred_clocking() == ClockingHint::Preference::RealTime;
dma_clocking_preference_ = dma_.last_valid()->preferred_clocking();
}
// MARK: - GPIP input.

View File

@ -126,7 +126,7 @@ void DMAController::set_floppy_drive_selection(bool drive1, bool drive2, bool si
}
void DMAController::set_floppy_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
fdc_.drives_[drive]->set_disk(disk);
fdc_.set_disk(disk, drive);
}
void DMAController::run_for(HalfCycles duration) {
@ -256,6 +256,5 @@ ClockingHint::Preference DMAController::preferred_clocking() {
}
void DMAController::set_activity_observer(Activity::Observer *observer) {
fdc_.drives_[0]->set_activity_observer(observer, "Internal", true);
fdc_.drives_[1]->set_activity_observer(observer, "External", true);
fdc_.set_activity_observer(observer);
}

View File

@ -56,30 +56,36 @@ class DMAController: public WD::WD1770::Delegate, public ClockingHint::Source, p
HalfCycles running_time_;
struct WD1772: public WD::WD1770 {
WD1772(): WD::WD1770(WD::WD1770::P1772) {
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
set_drive(drives_[0]);
emplace_drives(2, 8000000, 300, 2);
set_is_double_density(true); // TODO: is this selectable on the ST?
}
void set_motor_on(bool motor_on) final {
drives_[0]->set_motor_on(motor_on);
drives_[1]->set_motor_on(motor_on);
for_all_drives([motor_on] (Storage::Disk::Drive &drive, size_t) {
drive.set_motor_on(motor_on);
});
}
void set_floppy_drive_selection(bool drive1, bool drive2, bool side2) {
// TODO: handle no drives and/or both drives selected.
if(drive1) {
set_drive(drives_[0]);
} else {
set_drive(drives_[1]);
}
set_drive(
(drive1 ? 1 : 0) |
(drive2 ? 2 : 0)
);
drives_[0]->set_head(side2);
drives_[1]->set_head(side2);
for_all_drives([side2] (Storage::Disk::Drive &drive, size_t) {
drive.set_head(side2);
});
}
void set_activity_observer(Activity::Observer *observer) {
get_drive(0).set_activity_observer(observer, "Internal", true);
get_drive(1).set_activity_observer(observer, "External", true);
}
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
get_drive(drive).set_disk(disk);
}
std::vector<std::shared_ptr<Storage::Disk::Drive>> drives_;
} fdc_;
void wd1770_did_change_output(WD::WD1770 *) final;

View File

@ -19,7 +19,6 @@ using namespace Commodore::C1540;
MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher) :
Storage::Disk::Controller(1000000),
m6502_(*this),
drive_(new Storage::Disk::Drive(1000000, 300, 2)),
serial_port_VIA_port_handler_(new SerialPortVIA(serial_port_VIA_)),
serial_port_(new SerialPort),
drive_VIA_(drive_VIA_port_handler_),
@ -37,7 +36,8 @@ MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(3));
// attach the only drive there is
set_drive(drive_);
emplace_drive(1000000, 300, 2);
set_drive(1);
std::string device_name;
uint32_t crc = 0;
@ -103,21 +103,21 @@ Cycles MachineBase::perform_bus_operation(CPU::MOS6502::BusOperation operation,
}
void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk) {
drive_->set_disk(disk);
get_drive().set_disk(disk);
}
void Machine::run_for(const Cycles cycles) {
m6502_.run_for(cycles);
bool drive_motor = drive_VIA_port_handler_.get_motor_enabled();
drive_->set_motor_on(drive_motor);
const bool drive_motor = drive_VIA_port_handler_.get_motor_enabled();
get_drive().set_motor_on(drive_motor);
if(drive_motor)
Storage::Disk::Controller::run_for(cycles);
}
void MachineBase::set_activity_observer(Activity::Observer *observer) {
drive_VIA_.bus_handler().set_activity_observer(observer);
drive_->set_activity_observer(observer, "Drive", false);
get_drive().set_activity_observer(observer, "Drive", false);
}
// MARK: - 6522 delegate
@ -154,7 +154,7 @@ void MachineBase::process_index_hole() {}
// MARK: - Drive VIA delegate
void MachineBase::drive_via_did_step_head(void *driveVIA, int direction) {
drive_->step(Storage::Disk::HeadPosition(direction, 2));
get_drive().step(Storage::Disk::HeadPosition(direction, 2));
}
void MachineBase::drive_via_did_set_data_density(void *driveVIA, int density) {

View File

@ -144,7 +144,6 @@ class MachineBase:
protected:
CPU::MOS6502::Processor<CPU::MOS6502::Personality::P6502, MachineBase, false> m6502_;
std::shared_ptr<Storage::Disk::Drive> drive_;
uint8_t ram_[0x800];
uint8_t rom_[0x4000];

View File

@ -11,13 +11,12 @@
using namespace Electron;
Plus3::Plus3() : WD1770(P1770) {
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
emplace_drives(2, 8000000, 300, 2);
set_control_register(last_control_, 0xff);
}
void Plus3::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
drives_[drive]->set_disk(disk);
get_drive(drive).set_disk(disk);
}
void Plus3::set_control_register(uint8_t control) {
@ -33,16 +32,15 @@ void Plus3::set_control_register(uint8_t control) {
void Plus3::set_control_register(uint8_t control, uint8_t changes) {
if(changes&3) {
switch(control&3) {
case 0: selected_drive_ = -1; set_drive(nullptr); break;
default: selected_drive_ = 0; set_drive(drives_[0]); break;
case 2: selected_drive_ = 1; set_drive(drives_[1]); break;
}
set_drive(control&3);
}
// Select the side on both drives at once.
if(changes & 0x04) {
drives_[0]->set_head((control & 0x04) ? 1 : 0);
drives_[1]->set_head((control & 0x04) ? 1 : 0);
get_drive(0).set_head((control & 0x04) ? 1 : 0);
get_drive(1).set_head((control & 0x04) ? 1 : 0);
}
if(changes & 0x08) set_is_double_density(!(control & 0x08));
}
@ -53,9 +51,7 @@ void Plus3::set_motor_on(bool on) {
}
void Plus3::set_activity_observer(Activity::Observer *observer) {
size_t index = 0;
for(const auto &drive: drives_) {
drive->set_activity_observer(observer, "Drive " + std::to_string(index+1), true);
++index;
}
for_all_drives([observer] (Storage::Disk::Drive &drive, size_t index) {
drive.set_activity_observer(observer, "Drive " + std::to_string(index+1), true);
});
}

View File

@ -24,8 +24,6 @@ class Plus3 : public WD::WD1770 {
private:
void set_control_register(uint8_t control, uint8_t changes);
std::vector<std::shared_ptr<Storage::Disk::Drive>> drives_;
int selected_drive_ = 0;
uint8_t last_control_ = 0;
void set_motor_on(bool on);

View File

@ -13,8 +13,7 @@ using namespace MSX;
DiskROM::DiskROM(const std::vector<uint8_t> &rom) :
WD1770(P1793),
rom_(rom) {
drives_[0] = std::make_shared<Storage::Disk::Drive>(8000000, 300, 2);
drives_[1] = std::make_shared<Storage::Disk::Drive>(8000000, 300, 2);
emplace_drives(2, 8000000, 300, 2);
set_is_double_density(true);
}
@ -23,18 +22,19 @@ void DiskROM::write(uint16_t address, uint8_t value, bool pc_is_outside_bios) {
case 0x7ff8: case 0x7ff9: case 0x7ffa: case 0x7ffb:
WD::WD1770::write(address, value);
break;
case 0x7ffc:
selected_head_ = value & 1;
drives_[0]->set_head(selected_head_);
drives_[1]->set_head(selected_head_);
break;
case 0x7ffc: {
const int selected_head = value & 1;
for_all_drives([selected_head] (Storage::Disk::Drive &drive, size_t index) {
drive.set_head(selected_head);
});
} break;
case 0x7ffd: {
selected_drive_ = value & 1;
set_drive(drives_[selected_drive_]);
set_drive(1 << (value & 1));
bool drive_motor = !!(value & 0x80);
drives_[0]->set_motor_on(drive_motor);
drives_[1]->set_motor_on(drive_motor);
const bool drive_motor = value & 0x80;
for_all_drives([drive_motor] (Storage::Disk::Drive &drive, size_t index) {
drive.set_motor_on(drive_motor);
});
} break;
}
}
@ -59,7 +59,7 @@ void DiskROM::run_for(HalfCycles half_cycles) {
}
void DiskROM::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
drives_[drive]->set_disk(disk);
get_drive(drive).set_disk(disk);
}
void DiskROM::set_head_load_request(bool head_load) {
@ -68,9 +68,7 @@ void DiskROM::set_head_load_request(bool head_load) {
}
void DiskROM::set_activity_observer(Activity::Observer *observer) {
size_t c = 1;
for(auto &drive: drives_) {
drive->set_activity_observer(observer, "Drive " + std::to_string(c), true);
++c;
}
for_all_drives([observer] (Storage::Disk::Drive &drive, size_t index) {
drive.set_activity_observer(observer, "Drive " + std::to_string(index), true);
});
}

View File

@ -36,9 +36,6 @@ class DiskROM: public ROMSlotHandler, public WD::WD1770 {
const std::vector<uint8_t> &rom_;
long int controller_cycles_ = 0;
size_t selected_drive_ = 0;
int selected_head_ = 0;
std::array<std::shared_ptr<Storage::Disk::Drive>, 2> drives_;
void set_head_load_request(bool head_load) final;
};

View File

@ -14,6 +14,7 @@ BD500::BD500() : DiskController(P1793, 9000000, Storage::Disk::Drive::ReadyType:
disable_basic_rom_ = true;
select_paged_item();
set_is_double_density(true);
set_drive(1);
}
void BD500::write(int address, uint8_t value) {
@ -23,6 +24,18 @@ void BD500::write(int address, uint8_t value) {
// if(address == 0x320) printf("Command %02x\n", value);
WD::WD1770::write(address, value);
}
if(address == 0x031a) {
// Drive select; kudos to iss of Oricutron for figuring this one out;
// cf. http://forum.defence-force.org/viewtopic.php?f=25&p=21409#p21393
switch(value & 0xe0) {
default: set_drive(0); break;
case 0x20: set_drive(1); break;
case 0x40: set_drive(2); break;
case 0x80: set_drive(4); break;
case 0xc0: set_drive(8); break;
}
}
}
uint8_t BD500::read(int address) {
@ -113,16 +126,16 @@ void BD500::access(int address) {
void BD500::set_head_load_request(bool head_load) {
// Turn all motors on or off; if off then unload the head instantly.
is_loading_head_ |= head_load;
for(auto &drive : drives_) {
if(drive) drive->set_motor_on(head_load);
}
for_all_drives([head_load] (Storage::Disk::Drive &drive, size_t) {
drive.set_motor_on(head_load);
});
if(!head_load) set_head_loaded(false);
}
void BD500::run_for(const Cycles cycles) {
// If a head load is in progress and the selected drive is now ready,
// declare head loaded.
if(is_loading_head_ && drives_[selected_drive_] && drives_[selected_drive_]->get_is_ready()) {
if(is_loading_head_ && get_drive().get_is_ready()) {
set_head_loaded(true);
is_loading_head_ = false;
}

View File

@ -14,15 +14,13 @@ namespace Oric {
class DiskController: public WD::WD1770 {
public:
DiskController(WD::WD1770::Personality personality, int clock_rate, Storage::Disk::Drive::ReadyType ready_type) :
WD::WD1770(personality), clock_rate_(clock_rate), ready_type_(ready_type) {}
WD::WD1770(personality), clock_rate_(clock_rate), ready_type_(ready_type) {
emplace_drives(4, clock_rate_, 300, 2, ready_type_);
// TODO: don't assume four drives?
}
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int d) {
const size_t drive = size_t(d);
if(!drives_[drive]) {
drives_[drive] = std::make_unique<Storage::Disk::Drive>(clock_rate_, 300, 2, ready_type_);
if(drive == selected_drive_) set_drive(drives_[drive]);
}
drives_[drive]->set_disk(disk);
get_drive(size_t(d)).set_disk(disk);
}
enum class PagedItem {
@ -44,14 +42,6 @@ class DiskController: public WD::WD1770 {
}
protected:
std::array<std::shared_ptr<Storage::Disk::Drive>, 4> drives_;
size_t selected_drive_ = 0;
void select_drive(size_t drive) {
if(drive != selected_drive_) {
selected_drive_ = drive;
set_drive(drives_[selected_drive_]);
}
}
Delegate *delegate_ = nullptr;
bool enable_overlay_ram_ = false;

View File

@ -20,11 +20,12 @@ Jasmin::Jasmin() : DiskController(P1770, 8000000, Storage::Disk::Drive::ReadyTyp
void Jasmin::write(int address, uint8_t value) {
switch(address) {
// Set side.
case 0x3f8:
for(auto &drive : drives_) {
if(drive) drive->set_head(value & 1);
}
break;
case 0x3f8: {
const int head = value & 1;
for_all_drives([head] (Storage::Disk::Drive &drive, size_t) {
drive.set_head(head);
});
} break;
case 0x3f9:
/* TODO: reset. */
@ -42,11 +43,11 @@ void Jasmin::write(int address, uint8_t value) {
select_paged_item();
break;
case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: {
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(false);
select_drive(size_t(address - 0x3fc));
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_);
} break;
case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
get_drive().set_motor_on(false);
set_drive(1 << (address - 0x3fc));
get_drive().set_motor_on(motor_on_);
break;
default:
return WD::WD1770::write(address, value);
@ -55,7 +56,7 @@ void Jasmin::write(int address, uint8_t value) {
void Jasmin::set_motor_on(bool on) {
motor_on_ = on;
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_);
get_drive().set_motor_on(motor_on_);
if(observer_) {
observer_->set_led_status("Jasmin", on);
}

View File

@ -33,16 +33,15 @@ void Microdisc::set_control_register(uint8_t control, uint8_t changes) {
// b65: drive select
if((changes >> 5)&3) {
selected_drive_ = (control >> 5)&3;
set_drive(drives_[selected_drive_]);
set_drive(1 << (control >> 5)&3);
}
// b4: side select
if(changes & 0x10) {
const int head = (control & 0x10) ? 1 : 0;
for(auto &drive : drives_) {
if(drive) drive->set_head(head);
}
for_all_drives([head] (Storage::Disk::Drive &drive, size_t) {
drive.set_head(head);
});
}
// b3: double density select (0 = double)
@ -86,9 +85,9 @@ void Microdisc::set_head_load_request(bool head_load) {
// The drive motors (at present: I believe **all drive motors** regardless of the selected drive) receive
// the current head load request state.
for(auto &drive : drives_) {
if(drive) drive->set_motor_on(head_load);
}
for_all_drives([head_load] (Storage::Disk::Drive &drive, size_t) {
drive.set_motor_on(head_load);
});
// A request to load the head results in a delay until the head is confirmed loaded. This delay is handled
// in ::run_for. A request to unload the head results in an instant answer that the head is unloaded.

View File

@ -44,8 +44,8 @@ class VideoOutput {
int v_sync_start_position_, v_sync_end_position_, counter_period_;
// Output target and device.
uint8_t *rgb_pixel_target_;
uint32_t *composite_pixel_target_;
uint8_t *rgb_pixel_target_ = nullptr;
uint32_t *composite_pixel_target_ = nullptr;
uint32_t colour_forms_[8];
Outputs::Display::InputDataType data_type_;

View File

@ -14,9 +14,10 @@ Controller::Controller(Cycles clock_rate) :
clock_rate_multiplier_(128000000 / clock_rate.as_integral()),
clock_rate_(clock_rate.as_integral() * clock_rate_multiplier_),
pll_(100, *this),
empty_drive_(new Drive(int(clock_rate.as_integral()), 1, 1)) {
empty_drive_(int(clock_rate.as_integral()), 1, 1),
drive_(&empty_drive_) {
empty_drive_.set_clocking_hint_observer(this);
set_expected_bit_length(Time(1));
set_drive(empty_drive_);
}
void Controller::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) {
@ -24,15 +25,28 @@ void Controller::set_component_prefers_clocking(ClockingHint::Source *component,
}
ClockingHint::Preference Controller::preferred_clocking() {
return (!drive_ || (drive_->preferred_clocking() == ClockingHint::Preference::None)) ? ClockingHint::Preference::None : ClockingHint::Preference::RealTime;
// Nominate RealTime clocking if any drive currently wants any clocking whatsoever.
// Otherwise, ::None will do.
for(auto &drive: drives_) {
if(drive.preferred_clocking() != ClockingHint::Preference::None) {
return ClockingHint::Preference::RealTime;
}
}
if(empty_drive_.preferred_clocking() != ClockingHint::Preference::None) {
return ClockingHint::Preference::RealTime;
}
return ClockingHint::Preference::None;
}
void Controller::run_for(const Cycles cycles) {
if(drive_) drive_->run_for(cycles);
for(auto &drive: drives_) {
drive.run_for(cycles);
}
empty_drive_.run_for(cycles);
}
Drive &Controller::get_drive() {
return *drive_.get();
return *drive_;
}
// MARK: - Drive::EventDelegate
@ -71,26 +85,37 @@ void Controller::digital_phase_locked_loop_output_bit(int value) {
if(is_reading_) process_input_bit(value);
}
void Controller::set_drive(std::shared_ptr<Drive> drive) {
if(drive_ != drive) {
ClockingHint::Preference former_prefernece = preferred_clocking();
// invalidate_track();
void Controller::set_drive(int index_mask) {
if(drive_selection_mask_ == index_mask) {
return;
}
if(drive_) {
drive_->set_event_delegate(nullptr);
drive_->set_clocking_hint_observer(nullptr);
}
drive_ = drive;
if(drive_) {
drive_->set_event_delegate(this);
drive_->set_clocking_hint_observer(this);
} else {
drive_ = empty_drive_;
}
ClockingHint::Preference former_prefernece = preferred_clocking();
if(preferred_clocking() != former_prefernece) {
update_clocking_observer();
// Stop receiving events from the current drive.
get_drive().set_event_delegate(nullptr);
// TODO: a transfer of writing state, if writing?
if(!index_mask) {
drive_ = &empty_drive_;
} else {
// 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.
size_t index = 0;
while(!(index_mask&1)) {
index_mask >>= 1;
++index;
}
drive_ = &drives_[index];
}
get_drive().set_event_delegate(this);
if(preferred_clocking() != former_prefernece) {
update_clocking_observer();
}
}

View File

@ -49,9 +49,30 @@ class Controller:
void run_for(const Cycles cycles);
/*!
Sets the current drive. This drive is the one the PLL listens to.
Sets the current drive(s). Normally this will be exactly one, but some machines allow
zero or multiple drives to be attached, with useless results.
*/
void set_drive(std::shared_ptr<Drive> drive);
void set_drive(int index_mask);
/*!
Adds a new drive to the drive list, returning its index.
*/
template<typename... Args> size_t emplace_drive(Args&&... args) {
drives_.emplace_back(std::forward<Args>(args)...);
drives_.back().set_clocking_hint_observer(this);
return drives_.size() - 1;
}
/*!
Adds @c count new drives to the drive list, returning the index of the final one added.
*/
template<typename... Args> size_t emplace_drives(size_t count, Args&&... args) {
while(count--) {
drives_.emplace_back(std::forward<Args>(args)...);
drives_.back().set_clocking_hint_observer(this);
}
return drives_.size() - 1;
}
/*!
Should be implemented by subclasses; communicates each bit that the PLL recognises.
@ -98,6 +119,18 @@ class Controller:
*/
Drive &get_drive();
Drive &get_drive(size_t index) {
return drives_[index];
}
void for_all_drives(const std::function<void(Drive &, size_t)> &func) {
size_t index = 0;
for(auto &drive: drives_) {
func(drive, index);
++index;
}
}
/*!
As per ClockingHint::Source.
*/
@ -113,9 +146,10 @@ class Controller:
DigitalPhaseLockedLoop<Controller> pll_;
friend DigitalPhaseLockedLoop<Controller>;
std::shared_ptr<Drive> drive_;
std::shared_ptr<Drive> empty_drive_;
Drive empty_drive_;
std::vector<Drive> drives_;
Drive *drive_;
int drive_selection_mask_ = 0xff;
// ClockingHint::Observer.
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final;

View File

@ -170,6 +170,7 @@ void Drive::set_motor_on(bool motor_is_on) {
// TODO: momentum.
if(motor_is_on) {
set_disk_is_rotating(true);
time_until_motor_transition = Cycles(0);
return;
}
@ -431,9 +432,9 @@ void Drive::set_disk_is_rotating(bool is_rotating) {
disk_is_rotating_ = is_rotating;
if(observer_) {
observer_->set_drive_motor_status(drive_name_, motor_input_is_on_);
observer_->set_drive_motor_status(drive_name_, disk_is_rotating_);
if(announce_motor_led_) {
observer_->set_led_status(drive_name_, motor_input_is_on_);
observer_->set_led_status(drive_name_, disk_is_rotating_);
}
}