1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-27 18:55:48 +00:00

Separates the 8272's drive selection signalling from actual drive ownership.

Thereby returns working motor control to the CPC.
This commit is contained in:
Thomas Harte 2017-09-11 21:25:26 -04:00
parent 96bf133924
commit d3c385b471
3 changed files with 36 additions and 30 deletions

View File

@ -119,11 +119,12 @@ void i8272::run_for(Cycles cycles) {
// Perform a step.
int direction = (drives_[c].target_head_position < drives_[c].head_position) ? -1 : 1;
printf("Target %d versus believed %d\n", drives_[c].target_head_position, drives_[c].head_position);
drives_[c].drive->step(direction);
select_drive(c);
get_drive().step(direction);
if(drives_[c].target_head_position >= 0) drives_[c].head_position += direction;
// Check for completion.
if(drives_[c].seek_is_satisfied()) {
if(seek_is_satisfied(c)) {
drives_[c].phase = Drive::CompletedSeeking;
drives_seeking_--;
break;
@ -192,12 +193,6 @@ uint8_t i8272::get_register(int address) {
}
}
void i8272::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
if(drive < 4 && drive >= 0) {
drives_[drive].drive->set_disk(disk);
}
}
#define BEGIN_SECTION() switch(resume_point_) { default:
#define END_SECTION() }
@ -235,7 +230,7 @@ void i8272::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
#define SET_DRIVE_HEAD_MFM() \
active_drive_ = command_[1]&3; \
active_head_ = (command_[1] >> 2)&1; \
set_drive(drives_[active_drive_].drive); \
select_drive(active_drive_); \
get_drive().set_head((unsigned int)active_head_); \
set_is_double_density(command_[0] & 0x40);
@ -503,7 +498,7 @@ void i8272::posit_event(int event_type) {
write_data:
printf("Write [deleted] data [%02x %02x %02x %02x ... %02x %02x]\n", command_[2], command_[3], command_[4], command_[5], command_[6], command_[8]);
if(drives_[active_drive_].drive->get_is_read_only()) {
if(get_drive().get_is_read_only()) {
SetNotWriteable();
goto abort;
}
@ -618,7 +613,7 @@ void i8272::posit_event(int event_type) {
// Performs format [/write] track.
format_track:
printf("Format track\n");
if(drives_[active_drive_].drive->get_is_read_only()) {
if(get_drive().get_is_read_only()) {
SetNotWriteable();
goto abort;
}
@ -711,6 +706,7 @@ void i8272::posit_event(int event_type) {
seek:
{
int drive = command_[1]&3;
select_drive(drive);
// Increment the seeking count if this drive wasn't already seeking.
if(drives_[drive].phase != Drive::Seeking) {
@ -740,7 +736,7 @@ void i8272::posit_event(int event_type) {
}
// Check whether any steps are even needed; if not then mark as completed already.
if(drives_[drive].seek_is_satisfied()) {
if(seek_is_satisfied(drive)) {
drives_[drive].phase = Drive::CompletedSeeking;
drives_seeking_--;
}
@ -792,12 +788,13 @@ void i8272::posit_event(int event_type) {
printf("Sense drive status\n");
{
int drive = command_[1] & 3;
select_drive(drive);
result_stack_.push_back(
(command_[1] & 7) | // drive and head number
0x08 | // single sided
(drives_[drive].drive->get_is_track_zero() ? 0x10 : 0x00) |
(drives_[drive].drive->get_is_ready() ? 0x20 : 0x00) |
(drives_[drive].drive->get_is_read_only() ? 0x40 : 0x00)
(get_drive().get_is_track_zero() ? 0x10 : 0x00) |
(get_drive().get_is_ready() ? 0x20 : 0x00) |
(get_drive().get_is_read_only() ? 0x40 : 0x00)
);
}
goto post_result;
@ -852,9 +849,9 @@ void i8272::posit_event(int event_type) {
END_SECTION()
}
bool i8272::Drive::seek_is_satisfied() {
return (target_head_position == head_position) ||
(target_head_position == -1 && drive->get_is_track_zero());
bool i8272::seek_is_satisfied(int drive) {
return (drives_[drive].target_head_position == drives_[drive].head_position) ||
(drives_[drive].target_head_position == -1 && get_drive().get_is_track_zero());
}
void i8272::set_dma_acknowledge(bool dack) {

View File

@ -39,10 +39,11 @@ class i8272: public Storage::Disk::MFMController {
void set_dma_acknowledge(bool dack);
void set_terminal_count(bool tc);
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive);
bool is_sleeping();
protected:
virtual void select_drive(int number) = 0;
private:
// The bus handler, for interrupt and DMA-driven usage.
BusHandler &bus_handler_;
@ -91,24 +92,20 @@ class i8272: public Storage::Disk::MFMController {
int steps_taken;
int target_head_position; // either an actual number, or -1 to indicate to step until track zero
/// @returns @c true if the currently queued-up seek or recalibrate has reached where it should be.
bool seek_is_satisfied();
// Head state.
int head_unload_delay[2];
bool head_is_loaded[2];
// The connected drive.
std::shared_ptr<Storage::Disk::Drive> drive;
Drive() :
head_position(0), phase(NotSeeking),
drive(new Storage::Disk::Drive(8000000, 300)), // TODO: these constants can't live here.
head_is_loaded{false, false},
head_unload_delay{0, 0} {};
} drives_[4];
int drives_seeking_;
/// @returns @c true if the selected drive, which is number @c drive, can stop seeking.
bool seek_is_satisfied(int drive);
// User-supplied parameters; as per the specify command.
int step_rate_time_;
int head_unload_time_;

View File

@ -582,13 +582,25 @@ 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)) {}
FDC() :
i8272(bus_handler_, Cycles(8000000)),
drive_(new Storage::Disk::Drive(8000000, 300)) {
set_drive(drive_);
}
void set_motor_on(bool on) {
// TODO: should set all motors on, not 8272.hjust the one active drive.
get_drive().set_motor_on(on);
drive_->set_motor_on(on);
}
void select_drive(int c) {
// TODO: support more than one drive.
}
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
drive_->set_disk(disk);
}
};