1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-23 03:29:04 +00:00

Introduces more granular clocking announcements to the Disk II.

As well as making it accept the clock rate it'll actually receive, to supply to the drives, so that they spin at the proper speed.
This commit is contained in:
Thomas Harte 2018-05-28 17:19:29 -04:00
parent f3fe711542
commit 928aab13dc
4 changed files with 74 additions and 66 deletions

View File

@ -19,9 +19,10 @@ namespace {
const uint8_t input_flux = 0x1;
}
DiskII::DiskII() :
DiskII::DiskII(int clock_rate) :
clock_rate_(clock_rate),
inputs_(input_command),
drives_{{2045454, 300, 1}, {2045454, 300, 1}}
drives_{{static_cast<unsigned int>(clock_rate), 300, 1}, {static_cast<unsigned int>(clock_rate), 300, 1}}
{
drives_[0].set_clocking_hint_observer(this);
drives_[1].set_clocking_hint_observer(this);
@ -75,7 +76,6 @@ void DiskII::select_drive(int drive) {
void DiskII::run_for(const Cycles cycles) {
if(preferred_clocking() == ClockingHint::Preference::None) return;
if(!controller_can_sleep_) {
int integer_cycles = cycles.as_int();
while(integer_cycles--) {
const int address = (state_ & 0xf0) | inputs_ | ((shift_register_&0x80) >> 6);
@ -96,7 +96,7 @@ void DiskII::run_for(const Cycles cycles) {
if(shift_register_ == is_write_protected() ? 0xff : 0x00) {
if(!drive_is_sleeping_[0]) drives_[0].run_for(Cycles(integer_cycles));
if(!drive_is_sleeping_[1]) drives_[1].run_for(Cycles(integer_cycles));
set_controller_can_sleep();
decide_clocking_preference();
return;
}
break;
@ -110,33 +110,38 @@ void DiskII::run_for(const Cycles cycles) {
drives_[active_drive_].write_bit(!!((state_ ^ address) & 0x80));
}
// TODO: surely there's a less heavyweight solution than this?
// TODO: surely there's a less heavyweight solution than inline updates?
if(!drive_is_sleeping_[0]) drives_[0].run_for(Cycles(1));
if(!drive_is_sleeping_[1]) drives_[1].run_for(Cycles(1));
}
} else {
if(!drive_is_sleeping_[0]) drives_[0].run_for(cycles);
if(!drive_is_sleeping_[1]) drives_[1].run_for(cycles);
}
set_controller_can_sleep();
decide_clocking_preference();
}
void DiskII::set_controller_can_sleep() {
// Permit the controller to sleep if it's in sense write protect mode, and the shift register
// has already filled with the result of shifting eight times.
bool controller_could_sleep = controller_can_sleep_;
controller_can_sleep_ =
(
(inputs_ == input_flux) &&
!motor_is_enabled_ &&
!shift_register_
) ||
(
(inputs_ == (input_command | input_flux)) &&
(shift_register_ == (is_write_protected() ? 0xff : 0x00))
);
if(controller_could_sleep != controller_can_sleep_)
void DiskII::decide_clocking_preference() {
ClockingHint::Preference prior_preference = clocking_preference_;
// If in read mode, clocking is either:
//
// just-in-time, if drives are running or the shift register has any 1s in it or a flux event hasn't yet passed; or
// none, given that drives are not running, the shift register has already emptied and there's no flux about to fire.
if(!(inputs_ & ~input_flux)) {
clocking_preference_ = (!motor_is_enabled_ && !shift_register_ && !(inputs_&input_flux)) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime;
}
// If in writing mode, clocking is real time.
if(inputs_ & input_mode) {
clocking_preference_ = ClockingHint::Preference::RealTime;
}
// If in sense-write-protect mode, clocking is just-in-time if the shift register hasn't yet filled with the value that
// corresponds to the current write protect status. Otherwise it is none.
if((inputs_ & ~input_flux) == input_command) {
clocking_preference_ = (shift_register_ == (is_write_protected() ? 0xff : 0x00)) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime;
}
// Announce a change if there was one.
if(prior_preference != clocking_preference_)
update_clocking_observer();
}
@ -195,18 +200,18 @@ void DiskII::set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk, int driv
void DiskII::process_event(const Storage::Disk::Track::Event &event) {
if(event.type == Storage::Disk::Track::Event::FluxTransition) {
inputs_ &= ~input_flux;
set_controller_can_sleep();
decide_clocking_preference();
}
}
void DiskII::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) {
drive_is_sleeping_[0] = drives_[0].preferred_clocking() == ClockingHint::Preference::None;
drive_is_sleeping_[1] = drives_[1].preferred_clocking() == ClockingHint::Preference::None;
update_clocking_observer();
decide_clocking_preference();
}
ClockingHint::Preference DiskII::preferred_clocking() {
return (controller_can_sleep_ && drive_is_sleeping_[0] && drive_is_sleeping_[1]) ? ClockingHint::Preference::None : ClockingHint::Preference::RealTime;
return clocking_preference_;
}
void DiskII::set_data_input(uint8_t input) {
@ -243,11 +248,11 @@ int DiskII::read_address(int address) {
break;
case 0xf:
if(!(inputs_ & input_mode))
drives_[active_drive_].begin_writing(Storage::Time(1, 2045454), false);
drives_[active_drive_].begin_writing(Storage::Time(1, clock_rate_), false);
inputs_ |= input_mode;
break;
}
set_controller_can_sleep();
decide_clocking_preference();
return (address & 1) ? 0xff : shift_register_;
}

View File

@ -31,7 +31,7 @@ class DiskII:
public ClockingHint::Source,
public ClockingHint::Observer {
public:
DiskII();
DiskII(int clock_rate);
/// Sets the current external value of the data bus.
void set_data_input(uint8_t input);
@ -97,6 +97,8 @@ class DiskII:
void process_event(const Storage::Disk::Track::Event &event) override;
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) override;
const int clock_rate_ = 0;
uint8_t state_ = 0;
uint8_t inputs_ = 0;
uint8_t shift_register_ = 0;
@ -108,11 +110,11 @@ class DiskII:
std::array<uint8_t, 256> state_machine_;
Storage::Disk::Drive drives_[2];
bool drive_is_sleeping_[2];
bool controller_can_sleep_ = false;
int active_drive_ = 0;
bool motor_is_enabled_ = false;
void set_controller_can_sleep();
void decide_clocking_preference();
ClockingHint::Preference clocking_preference_ = ClockingHint::Preference::RealTime;
uint8_t data_input_ = 0;
};

View File

@ -10,7 +10,7 @@
using namespace AppleII;
DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sector) {
DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sector) : diskii_(2045454) {
auto roms = rom_fetcher(
"DiskII",
{

View File

@ -212,7 +212,8 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
ay8910_(audio_queue_),
speaker_(ay8910_),
via_port_handler_(audio_queue_, ay8910_, speaker_, tape_player_, keyboard_),
via_(via_port_handler_) {
via_(via_port_handler_),
diskii_(2000000) {
set_clock_rate(1000000);
via_port_handler_.set_interrupt_delegate(this);
tape_player_.set_delegate(this);