mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-07 23:25:00 +00:00
Merge pull request #749 from TomHarte/DiskIndicator
Moves ownership of drives inside Disk::Controller.
This commit is contained in:
@@ -19,12 +19,10 @@ using namespace Analyser::Static::Commodore;
|
|||||||
|
|
||||||
class CommodoreGCRParser: public Storage::Disk::Controller {
|
class CommodoreGCRParser: public Storage::Disk::Controller {
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<Storage::Disk::Drive> drive;
|
|
||||||
|
|
||||||
CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
|
CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
|
||||||
drive = std::make_shared<Storage::Disk::Drive>(4000000, 300, 2);
|
emplace_drive(4000000, 300, 2);
|
||||||
set_drive(drive);
|
set_drive(1);
|
||||||
drive->set_motor_on(true);
|
get_drive().set_motor_on(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sector {
|
struct Sector {
|
||||||
@@ -61,6 +59,10 @@ class CommodoreGCRParser: public Storage::Disk::Controller {
|
|||||||
return get_sector(sector);
|
return get_sector(sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
|
||||||
|
get_drive().set_disk(disk);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int shift_register_;
|
unsigned int shift_register_;
|
||||||
int index_count_;
|
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> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk) {
|
||||||
std::vector<File> files;
|
std::vector<File> files;
|
||||||
CommodoreGCRParser parser;
|
CommodoreGCRParser parser;
|
||||||
parser.drive->set_disk(disk);
|
parser.set_disk(disk);
|
||||||
|
|
||||||
// find any sector whatsoever to establish the current track
|
// find any sector whatsoever to establish the current track
|
||||||
std::shared_ptr<CommodoreGCRParser::Sector> sector;
|
std::shared_ptr<CommodoreGCRParser::Sector> sector;
|
||||||
|
@@ -661,17 +661,15 @@ class KeyboardState: public GI::AY38910::PortHandler {
|
|||||||
class FDC: public Intel::i8272::i8272 {
|
class FDC: public Intel::i8272::i8272 {
|
||||||
private:
|
private:
|
||||||
Intel::i8272::BusHandler bus_handler_;
|
Intel::i8272::BusHandler bus_handler_;
|
||||||
std::shared_ptr<Storage::Disk::Drive> drive_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FDC() :
|
FDC() : i8272(bus_handler_, Cycles(8000000)) {
|
||||||
i8272(bus_handler_, Cycles(8000000)),
|
emplace_drive(8000000, 300, 1);
|
||||||
drive_(new Storage::Disk::Drive(8000000, 300, 1)) {
|
set_drive(1);
|
||||||
set_drive(drive_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_motor_on(bool on) {
|
void set_motor_on(bool on) {
|
||||||
drive_->set_motor_on(on);
|
get_drive().set_motor_on(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
void select_drive(int c) {
|
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) {
|
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) {
|
void set_activity_observer(Activity::Observer *observer) {
|
||||||
drive_->set_activity_observer(observer, "Drive 1", true);
|
get_drive().set_activity_observer(observer, "Drive 1", true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -441,7 +441,8 @@ class ConcreteMachine:
|
|||||||
// Advance the relevant counters.
|
// Advance the relevant counters.
|
||||||
cycles_since_audio_update_ += length;
|
cycles_since_audio_update_ += length;
|
||||||
mfp_ += length;
|
mfp_ += length;
|
||||||
dma_ += length;
|
if(dma_clocking_preference_ != ClockingHint::Preference::None)
|
||||||
|
dma_ += length;
|
||||||
keyboard_acia_ += length;
|
keyboard_acia_ += length;
|
||||||
midi_acia_ += length;
|
midi_acia_ += length;
|
||||||
bus_phase_ += length;
|
bus_phase_ += length;
|
||||||
@@ -462,7 +463,7 @@ class ConcreteMachine:
|
|||||||
mfp_.flush();
|
mfp_.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dma_is_realtime_) {
|
if(dma_clocking_preference_ == ClockingHint::Preference::RealTime) {
|
||||||
dma_.flush();
|
dma_.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,7 +532,7 @@ class ConcreteMachine:
|
|||||||
bool may_defer_acias_ = true;
|
bool may_defer_acias_ = true;
|
||||||
bool keyboard_needs_clock_ = false;
|
bool keyboard_needs_clock_ = false;
|
||||||
bool mfp_is_realtime_ = 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 {
|
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
|
// 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).
|
// 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);
|
(midi_acia_.last_valid()->preferred_clocking() != ClockingHint::Preference::RealTime);
|
||||||
keyboard_needs_clock_ = ikbd_.preferred_clocking() != ClockingHint::Preference::None;
|
keyboard_needs_clock_ = ikbd_.preferred_clocking() != ClockingHint::Preference::None;
|
||||||
mfp_is_realtime_ = mfp_.last_valid()->preferred_clocking() == ClockingHint::Preference::RealTime;
|
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.
|
// MARK: - GPIP input.
|
||||||
|
@@ -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) {
|
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) {
|
void DMAController::run_for(HalfCycles duration) {
|
||||||
@@ -256,6 +256,5 @@ ClockingHint::Preference DMAController::preferred_clocking() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DMAController::set_activity_observer(Activity::Observer *observer) {
|
void DMAController::set_activity_observer(Activity::Observer *observer) {
|
||||||
fdc_.drives_[0]->set_activity_observer(observer, "Internal", true);
|
fdc_.set_activity_observer(observer);
|
||||||
fdc_.drives_[1]->set_activity_observer(observer, "External", true);
|
|
||||||
}
|
}
|
||||||
|
@@ -56,30 +56,36 @@ class DMAController: public WD::WD1770::Delegate, public ClockingHint::Source, p
|
|||||||
HalfCycles running_time_;
|
HalfCycles running_time_;
|
||||||
struct WD1772: public WD::WD1770 {
|
struct WD1772: public WD::WD1770 {
|
||||||
WD1772(): WD::WD1770(WD::WD1770::P1772) {
|
WD1772(): WD::WD1770(WD::WD1770::P1772) {
|
||||||
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
|
emplace_drives(2, 8000000, 300, 2);
|
||||||
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
|
|
||||||
set_drive(drives_[0]);
|
|
||||||
set_is_double_density(true); // TODO: is this selectable on the ST?
|
set_is_double_density(true); // TODO: is this selectable on the ST?
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_motor_on(bool motor_on) final {
|
void set_motor_on(bool motor_on) final {
|
||||||
drives_[0]->set_motor_on(motor_on);
|
for_all_drives([motor_on] (Storage::Disk::Drive &drive, size_t) {
|
||||||
drives_[1]->set_motor_on(motor_on);
|
drive.set_motor_on(motor_on);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_floppy_drive_selection(bool drive1, bool drive2, bool side2) {
|
void set_floppy_drive_selection(bool drive1, bool drive2, bool side2) {
|
||||||
// TODO: handle no drives and/or both drives selected.
|
set_drive(
|
||||||
if(drive1) {
|
(drive1 ? 1 : 0) |
|
||||||
set_drive(drives_[0]);
|
(drive2 ? 2 : 0)
|
||||||
} else {
|
);
|
||||||
set_drive(drives_[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
drives_[0]->set_head(side2);
|
for_all_drives([side2] (Storage::Disk::Drive &drive, size_t) {
|
||||||
drives_[1]->set_head(side2);
|
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_;
|
} fdc_;
|
||||||
|
|
||||||
void wd1770_did_change_output(WD::WD1770 *) final;
|
void wd1770_did_change_output(WD::WD1770 *) final;
|
||||||
|
@@ -19,7 +19,6 @@ using namespace Commodore::C1540;
|
|||||||
MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher) :
|
MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||||
Storage::Disk::Controller(1000000),
|
Storage::Disk::Controller(1000000),
|
||||||
m6502_(*this),
|
m6502_(*this),
|
||||||
drive_(new Storage::Disk::Drive(1000000, 300, 2)),
|
|
||||||
serial_port_VIA_port_handler_(new SerialPortVIA(serial_port_VIA_)),
|
serial_port_VIA_port_handler_(new SerialPortVIA(serial_port_VIA_)),
|
||||||
serial_port_(new SerialPort),
|
serial_port_(new SerialPort),
|
||||||
drive_VIA_(drive_VIA_port_handler_),
|
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));
|
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(3));
|
||||||
|
|
||||||
// attach the only drive there is
|
// attach the only drive there is
|
||||||
set_drive(drive_);
|
emplace_drive(1000000, 300, 2);
|
||||||
|
set_drive(1);
|
||||||
|
|
||||||
std::string device_name;
|
std::string device_name;
|
||||||
uint32_t crc = 0;
|
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) {
|
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) {
|
void Machine::run_for(const Cycles cycles) {
|
||||||
m6502_.run_for(cycles);
|
m6502_.run_for(cycles);
|
||||||
|
|
||||||
bool drive_motor = drive_VIA_port_handler_.get_motor_enabled();
|
const bool drive_motor = drive_VIA_port_handler_.get_motor_enabled();
|
||||||
drive_->set_motor_on(drive_motor);
|
get_drive().set_motor_on(drive_motor);
|
||||||
if(drive_motor)
|
if(drive_motor)
|
||||||
Storage::Disk::Controller::run_for(cycles);
|
Storage::Disk::Controller::run_for(cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MachineBase::set_activity_observer(Activity::Observer *observer) {
|
void MachineBase::set_activity_observer(Activity::Observer *observer) {
|
||||||
drive_VIA_.bus_handler().set_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
|
// MARK: - 6522 delegate
|
||||||
@@ -154,7 +154,7 @@ void MachineBase::process_index_hole() {}
|
|||||||
// MARK: - Drive VIA delegate
|
// MARK: - Drive VIA delegate
|
||||||
|
|
||||||
void MachineBase::drive_via_did_step_head(void *driveVIA, int direction) {
|
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) {
|
void MachineBase::drive_via_did_set_data_density(void *driveVIA, int density) {
|
||||||
|
@@ -144,7 +144,6 @@ class MachineBase:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
CPU::MOS6502::Processor<CPU::MOS6502::Personality::P6502, MachineBase, false> m6502_;
|
CPU::MOS6502::Processor<CPU::MOS6502::Personality::P6502, MachineBase, false> m6502_;
|
||||||
std::shared_ptr<Storage::Disk::Drive> drive_;
|
|
||||||
|
|
||||||
uint8_t ram_[0x800];
|
uint8_t ram_[0x800];
|
||||||
uint8_t rom_[0x4000];
|
uint8_t rom_[0x4000];
|
||||||
|
@@ -11,13 +11,12 @@
|
|||||||
using namespace Electron;
|
using namespace Electron;
|
||||||
|
|
||||||
Plus3::Plus3() : WD1770(P1770) {
|
Plus3::Plus3() : WD1770(P1770) {
|
||||||
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
|
emplace_drives(2, 8000000, 300, 2);
|
||||||
drives_.emplace_back(new Storage::Disk::Drive(8000000, 300, 2));
|
|
||||||
set_control_register(last_control_, 0xff);
|
set_control_register(last_control_, 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plus3::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
|
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) {
|
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) {
|
void Plus3::set_control_register(uint8_t control, uint8_t changes) {
|
||||||
if(changes&3) {
|
if(changes&3) {
|
||||||
switch(control&3) {
|
set_drive(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select the side on both drives at once.
|
||||||
if(changes & 0x04) {
|
if(changes & 0x04) {
|
||||||
drives_[0]->set_head((control & 0x04) ? 1 : 0);
|
get_drive(0).set_head((control & 0x04) ? 1 : 0);
|
||||||
drives_[1]->set_head((control & 0x04) ? 1 : 0);
|
get_drive(1).set_head((control & 0x04) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(changes & 0x08) set_is_double_density(!(control & 0x08));
|
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) {
|
void Plus3::set_activity_observer(Activity::Observer *observer) {
|
||||||
size_t index = 0;
|
for_all_drives([observer] (Storage::Disk::Drive &drive, size_t index) {
|
||||||
for(const auto &drive: drives_) {
|
drive.set_activity_observer(observer, "Drive " + std::to_string(index+1), true);
|
||||||
drive->set_activity_observer(observer, "Drive " + std::to_string(index+1), true);
|
});
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -24,8 +24,6 @@ class Plus3 : public WD::WD1770 {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void set_control_register(uint8_t control, uint8_t changes);
|
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;
|
uint8_t last_control_ = 0;
|
||||||
|
|
||||||
void set_motor_on(bool on);
|
void set_motor_on(bool on);
|
||||||
|
@@ -13,8 +13,7 @@ using namespace MSX;
|
|||||||
DiskROM::DiskROM(const std::vector<uint8_t> &rom) :
|
DiskROM::DiskROM(const std::vector<uint8_t> &rom) :
|
||||||
WD1770(P1793),
|
WD1770(P1793),
|
||||||
rom_(rom) {
|
rom_(rom) {
|
||||||
drives_[0] = std::make_shared<Storage::Disk::Drive>(8000000, 300, 2);
|
emplace_drives(2, 8000000, 300, 2);
|
||||||
drives_[1] = std::make_shared<Storage::Disk::Drive>(8000000, 300, 2);
|
|
||||||
set_is_double_density(true);
|
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:
|
case 0x7ff8: case 0x7ff9: case 0x7ffa: case 0x7ffb:
|
||||||
WD::WD1770::write(address, value);
|
WD::WD1770::write(address, value);
|
||||||
break;
|
break;
|
||||||
case 0x7ffc:
|
case 0x7ffc: {
|
||||||
selected_head_ = value & 1;
|
const int selected_head = value & 1;
|
||||||
drives_[0]->set_head(selected_head_);
|
for_all_drives([selected_head] (Storage::Disk::Drive &drive, size_t index) {
|
||||||
drives_[1]->set_head(selected_head_);
|
drive.set_head(selected_head);
|
||||||
break;
|
});
|
||||||
|
} break;
|
||||||
case 0x7ffd: {
|
case 0x7ffd: {
|
||||||
selected_drive_ = value & 1;
|
set_drive(1 << (value & 1));
|
||||||
set_drive(drives_[selected_drive_]);
|
|
||||||
|
|
||||||
bool drive_motor = !!(value & 0x80);
|
const bool drive_motor = value & 0x80;
|
||||||
drives_[0]->set_motor_on(drive_motor);
|
for_all_drives([drive_motor] (Storage::Disk::Drive &drive, size_t index) {
|
||||||
drives_[1]->set_motor_on(drive_motor);
|
drive.set_motor_on(drive_motor);
|
||||||
|
});
|
||||||
} break;
|
} 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) {
|
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) {
|
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) {
|
void DiskROM::set_activity_observer(Activity::Observer *observer) {
|
||||||
size_t c = 1;
|
for_all_drives([observer] (Storage::Disk::Drive &drive, size_t index) {
|
||||||
for(auto &drive: drives_) {
|
drive.set_activity_observer(observer, "Drive " + std::to_string(index), true);
|
||||||
drive->set_activity_observer(observer, "Drive " + std::to_string(c), true);
|
});
|
||||||
++c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -36,9 +36,6 @@ class DiskROM: public ROMSlotHandler, public WD::WD1770 {
|
|||||||
const std::vector<uint8_t> &rom_;
|
const std::vector<uint8_t> &rom_;
|
||||||
|
|
||||||
long int controller_cycles_ = 0;
|
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;
|
void set_head_load_request(bool head_load) final;
|
||||||
};
|
};
|
||||||
|
@@ -14,6 +14,7 @@ BD500::BD500() : DiskController(P1793, 9000000, Storage::Disk::Drive::ReadyType:
|
|||||||
disable_basic_rom_ = true;
|
disable_basic_rom_ = true;
|
||||||
select_paged_item();
|
select_paged_item();
|
||||||
set_is_double_density(true);
|
set_is_double_density(true);
|
||||||
|
set_drive(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BD500::write(int address, uint8_t value) {
|
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);
|
// if(address == 0x320) printf("Command %02x\n", value);
|
||||||
WD::WD1770::write(address, 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) {
|
uint8_t BD500::read(int address) {
|
||||||
@@ -113,16 +126,16 @@ void BD500::access(int address) {
|
|||||||
void BD500::set_head_load_request(bool head_load) {
|
void BD500::set_head_load_request(bool head_load) {
|
||||||
// Turn all motors on or off; if off then unload the head instantly.
|
// Turn all motors on or off; if off then unload the head instantly.
|
||||||
is_loading_head_ |= head_load;
|
is_loading_head_ |= head_load;
|
||||||
for(auto &drive : drives_) {
|
for_all_drives([head_load] (Storage::Disk::Drive &drive, size_t) {
|
||||||
if(drive) drive->set_motor_on(head_load);
|
drive.set_motor_on(head_load);
|
||||||
}
|
});
|
||||||
if(!head_load) set_head_loaded(false);
|
if(!head_load) set_head_loaded(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BD500::run_for(const Cycles cycles) {
|
void BD500::run_for(const Cycles cycles) {
|
||||||
// If a head load is in progress and the selected drive is now ready,
|
// If a head load is in progress and the selected drive is now ready,
|
||||||
// declare head loaded.
|
// 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);
|
set_head_loaded(true);
|
||||||
is_loading_head_ = false;
|
is_loading_head_ = false;
|
||||||
}
|
}
|
||||||
|
@@ -14,15 +14,13 @@ namespace Oric {
|
|||||||
class DiskController: public WD::WD1770 {
|
class DiskController: public WD::WD1770 {
|
||||||
public:
|
public:
|
||||||
DiskController(WD::WD1770::Personality personality, int clock_rate, Storage::Disk::Drive::ReadyType ready_type) :
|
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) {
|
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int d) {
|
||||||
const size_t drive = size_t(d);
|
get_drive(size_t(d)).set_disk(disk);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class PagedItem {
|
enum class PagedItem {
|
||||||
@@ -44,14 +42,6 @@ class DiskController: public WD::WD1770 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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;
|
Delegate *delegate_ = nullptr;
|
||||||
|
|
||||||
bool enable_overlay_ram_ = false;
|
bool enable_overlay_ram_ = false;
|
||||||
|
@@ -20,11 +20,12 @@ Jasmin::Jasmin() : DiskController(P1770, 8000000, Storage::Disk::Drive::ReadyTyp
|
|||||||
void Jasmin::write(int address, uint8_t value) {
|
void Jasmin::write(int address, uint8_t value) {
|
||||||
switch(address) {
|
switch(address) {
|
||||||
// Set side.
|
// Set side.
|
||||||
case 0x3f8:
|
case 0x3f8: {
|
||||||
for(auto &drive : drives_) {
|
const int head = value & 1;
|
||||||
if(drive) drive->set_head(value & 1);
|
for_all_drives([head] (Storage::Disk::Drive &drive, size_t) {
|
||||||
}
|
drive.set_head(head);
|
||||||
break;
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
case 0x3f9:
|
case 0x3f9:
|
||||||
/* TODO: reset. */
|
/* TODO: reset. */
|
||||||
@@ -42,11 +43,11 @@ void Jasmin::write(int address, uint8_t value) {
|
|||||||
select_paged_item();
|
select_paged_item();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: {
|
case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
|
||||||
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(false);
|
get_drive().set_motor_on(false);
|
||||||
select_drive(size_t(address - 0x3fc));
|
set_drive(1 << (address - 0x3fc));
|
||||||
if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_);
|
get_drive().set_motor_on(motor_on_);
|
||||||
} break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return WD::WD1770::write(address, value);
|
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) {
|
void Jasmin::set_motor_on(bool on) {
|
||||||
motor_on_ = 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_) {
|
if(observer_) {
|
||||||
observer_->set_led_status("Jasmin", on);
|
observer_->set_led_status("Jasmin", on);
|
||||||
}
|
}
|
||||||
|
@@ -33,16 +33,15 @@ void Microdisc::set_control_register(uint8_t control, uint8_t changes) {
|
|||||||
|
|
||||||
// b65: drive select
|
// b65: drive select
|
||||||
if((changes >> 5)&3) {
|
if((changes >> 5)&3) {
|
||||||
selected_drive_ = (control >> 5)&3;
|
set_drive(1 << (control >> 5)&3);
|
||||||
set_drive(drives_[selected_drive_]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// b4: side select
|
// b4: side select
|
||||||
if(changes & 0x10) {
|
if(changes & 0x10) {
|
||||||
const int head = (control & 0x10) ? 1 : 0;
|
const int head = (control & 0x10) ? 1 : 0;
|
||||||
for(auto &drive : drives_) {
|
for_all_drives([head] (Storage::Disk::Drive &drive, size_t) {
|
||||||
if(drive) drive->set_head(head);
|
drive.set_head(head);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// b3: double density select (0 = double)
|
// 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 drive motors (at present: I believe **all drive motors** regardless of the selected drive) receive
|
||||||
// the current head load request state.
|
// the current head load request state.
|
||||||
for(auto &drive : drives_) {
|
for_all_drives([head_load] (Storage::Disk::Drive &drive, size_t) {
|
||||||
if(drive) drive->set_motor_on(head_load);
|
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
|
// 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.
|
// in ::run_for. A request to unload the head results in an instant answer that the head is unloaded.
|
||||||
|
@@ -44,8 +44,8 @@ class VideoOutput {
|
|||||||
int v_sync_start_position_, v_sync_end_position_, counter_period_;
|
int v_sync_start_position_, v_sync_end_position_, counter_period_;
|
||||||
|
|
||||||
// Output target and device.
|
// Output target and device.
|
||||||
uint8_t *rgb_pixel_target_;
|
uint8_t *rgb_pixel_target_ = nullptr;
|
||||||
uint32_t *composite_pixel_target_;
|
uint32_t *composite_pixel_target_ = nullptr;
|
||||||
uint32_t colour_forms_[8];
|
uint32_t colour_forms_[8];
|
||||||
Outputs::Display::InputDataType data_type_;
|
Outputs::Display::InputDataType data_type_;
|
||||||
|
|
||||||
|
@@ -14,9 +14,10 @@ Controller::Controller(Cycles clock_rate) :
|
|||||||
clock_rate_multiplier_(128000000 / clock_rate.as_integral()),
|
clock_rate_multiplier_(128000000 / clock_rate.as_integral()),
|
||||||
clock_rate_(clock_rate.as_integral() * clock_rate_multiplier_),
|
clock_rate_(clock_rate.as_integral() * clock_rate_multiplier_),
|
||||||
pll_(100, *this),
|
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_expected_bit_length(Time(1));
|
||||||
set_drive(empty_drive_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) {
|
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() {
|
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) {
|
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() {
|
Drive &Controller::get_drive() {
|
||||||
return *drive_.get();
|
return *drive_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Drive::EventDelegate
|
// MARK: - Drive::EventDelegate
|
||||||
@@ -71,26 +85,37 @@ void Controller::digital_phase_locked_loop_output_bit(int value) {
|
|||||||
if(is_reading_) process_input_bit(value);
|
if(is_reading_) process_input_bit(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::set_drive(std::shared_ptr<Drive> drive) {
|
void Controller::set_drive(int index_mask) {
|
||||||
if(drive_ != drive) {
|
if(drive_selection_mask_ == index_mask) {
|
||||||
ClockingHint::Preference former_prefernece = preferred_clocking();
|
return;
|
||||||
// invalidate_track();
|
}
|
||||||
|
|
||||||
if(drive_) {
|
ClockingHint::Preference former_prefernece = preferred_clocking();
|
||||||
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_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(preferred_clocking() != former_prefernece) {
|
// Stop receiving events from the current drive.
|
||||||
update_clocking_observer();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,9 +49,30 @@ class Controller:
|
|||||||
void run_for(const Cycles cycles);
|
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.
|
Should be implemented by subclasses; communicates each bit that the PLL recognises.
|
||||||
@@ -98,6 +119,18 @@ class Controller:
|
|||||||
*/
|
*/
|
||||||
Drive &get_drive();
|
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.
|
As per ClockingHint::Source.
|
||||||
*/
|
*/
|
||||||
@@ -113,9 +146,10 @@ class Controller:
|
|||||||
DigitalPhaseLockedLoop<Controller> pll_;
|
DigitalPhaseLockedLoop<Controller> pll_;
|
||||||
friend DigitalPhaseLockedLoop<Controller>;
|
friend DigitalPhaseLockedLoop<Controller>;
|
||||||
|
|
||||||
std::shared_ptr<Drive> drive_;
|
Drive empty_drive_;
|
||||||
|
std::vector<Drive> drives_;
|
||||||
std::shared_ptr<Drive> empty_drive_;
|
Drive *drive_;
|
||||||
|
int drive_selection_mask_ = 0xff;
|
||||||
|
|
||||||
// ClockingHint::Observer.
|
// ClockingHint::Observer.
|
||||||
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final;
|
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final;
|
||||||
|
@@ -170,6 +170,7 @@ void Drive::set_motor_on(bool motor_is_on) {
|
|||||||
// TODO: momentum.
|
// TODO: momentum.
|
||||||
if(motor_is_on) {
|
if(motor_is_on) {
|
||||||
set_disk_is_rotating(true);
|
set_disk_is_rotating(true);
|
||||||
|
time_until_motor_transition = Cycles(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,9 +432,9 @@ void Drive::set_disk_is_rotating(bool is_rotating) {
|
|||||||
disk_is_rotating_ = is_rotating;
|
disk_is_rotating_ = is_rotating;
|
||||||
|
|
||||||
if(observer_) {
|
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_) {
|
if(announce_motor_led_) {
|
||||||
observer_->set_led_status(drive_name_, motor_input_is_on_);
|
observer_->set_led_status(drive_name_, disk_is_rotating_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user