mirror of
https://github.com/TomHarte/CLK.git
synced 2024-10-20 06:25:01 +00:00
Merge pull request #702 from TomHarte/NZStory
Corrects WD track-zero and write-protect flags.
This commit is contained in:
commit
42dd70dbff
@ -61,20 +61,28 @@ uint8_t WD1770::get_register(int address) {
|
|||||||
status.interrupt_request = false;
|
status.interrupt_request = false;
|
||||||
});
|
});
|
||||||
uint8_t status =
|
uint8_t status =
|
||||||
(status_.write_protect ? Flag::WriteProtect : 0) |
|
(status_.crc_error ? Flag::CRCError : 0) |
|
||||||
(status_.crc_error ? Flag::CRCError : 0) |
|
(status_.busy ? Flag::Busy : 0);
|
||||||
(status_.busy ? Flag::Busy : 0);
|
|
||||||
|
// Per Jean Louis-Guérin's documentation:
|
||||||
|
//
|
||||||
|
// * the write-protect bit is locked into place by a type 2 or type 3 command, but is
|
||||||
|
// read live after a type 1.
|
||||||
|
// * the track 0 bit is captured during a type 1 instruction and lost upon any other type,
|
||||||
|
// it is not live sampled.
|
||||||
switch(status_.type) {
|
switch(status_.type) {
|
||||||
case Status::One:
|
case Status::One:
|
||||||
status |=
|
status |=
|
||||||
(get_drive().get_is_track_zero() ? Flag::TrackZero : 0) |
|
(status_.track_zero ? Flag::TrackZero : 0) |
|
||||||
(status_.seek_error ? Flag::SeekError : 0);
|
(status_.seek_error ? Flag::SeekError : 0) |
|
||||||
// TODO: index hole
|
(get_drive().get_is_read_only() ? Flag::WriteProtect : 0) |
|
||||||
|
(get_drive().get_index_pulse() ? Flag::Index : 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Status::Two:
|
case Status::Two:
|
||||||
case Status::Three:
|
case Status::Three:
|
||||||
status |=
|
status |=
|
||||||
|
(status_.write_protect ? Flag::WriteProtect : 0) |
|
||||||
(status_.record_type ? Flag::RecordType : 0) |
|
(status_.record_type ? Flag::RecordType : 0) |
|
||||||
(status_.lost_data ? Flag::LostData : 0) |
|
(status_.lost_data ? Flag::LostData : 0) |
|
||||||
(status_.data_request ? Flag::DataRequest : 0) |
|
(status_.data_request ? Flag::DataRequest : 0) |
|
||||||
@ -91,7 +99,7 @@ uint8_t WD1770::get_register(int address) {
|
|||||||
if(status_.type == Status::One)
|
if(status_.type == Status::One)
|
||||||
status |= (status_.spin_up ? Flag::SpinUp : 0);
|
status |= (status_.spin_up ? Flag::SpinUp : 0);
|
||||||
}
|
}
|
||||||
LOG("Returned status " << PADHEX(2) << int(status) << " of type " << 1+int(status_.type));
|
// LOG("Returned status " << PADHEX(2) << int(status) << " of type " << 1+int(status_.type));
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
@ -192,6 +200,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.type = Status::One;
|
status.type = Status::One;
|
||||||
status.data_request = false;
|
status.data_request = false;
|
||||||
|
status.spin_up = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if(!(interesting_event_mask_ & int(new_event_type))) return;
|
if(!(interesting_event_mask_ & int(new_event_type))) return;
|
||||||
@ -217,6 +226,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.busy = true;
|
status.busy = true;
|
||||||
status.interrupt_request = false;
|
status.interrupt_request = false;
|
||||||
|
status.track_zero = false; // Always reset by a non-type 1; so reset regardless and set properly later.
|
||||||
});
|
});
|
||||||
|
|
||||||
LOG("Starting " << PADHEX(2) << int(command_));
|
LOG("Starting " << PADHEX(2) << int(command_));
|
||||||
@ -282,7 +292,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
perform_seek_or_restore_command:
|
perform_seek_or_restore_command:
|
||||||
if(track_ == data_) goto verify;
|
if(track_ == data_) goto verify_seek;
|
||||||
step_direction_ = (data_ > track_);
|
step_direction_ = (data_ > track_);
|
||||||
|
|
||||||
adjust_track:
|
adjust_track:
|
||||||
@ -291,7 +301,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
perform_step:
|
perform_step:
|
||||||
if(!step_direction_ && get_drive().get_is_track_zero()) {
|
if(!step_direction_ && get_drive().get_is_track_zero()) {
|
||||||
track_ = 0;
|
track_ = 0;
|
||||||
goto verify;
|
goto verify_seek;
|
||||||
}
|
}
|
||||||
get_drive().step(Storage::Disk::HeadPosition(step_direction_ ? 1 : -1));
|
get_drive().step(Storage::Disk::HeadPosition(step_direction_ ? 1 : -1));
|
||||||
Cycles::IntType time_to_wait;
|
Cycles::IntType time_to_wait;
|
||||||
@ -303,14 +313,17 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
case 3: time_to_wait = (personality_ == P1772) ? 3 : 30; break;
|
case 3: time_to_wait = (personality_ == P1772) ? 3 : 30; break;
|
||||||
}
|
}
|
||||||
WAIT_FOR_TIME(time_to_wait);
|
WAIT_FOR_TIME(time_to_wait);
|
||||||
if(command_ >> 5) goto verify;
|
if(command_ >> 5) goto verify_seek;
|
||||||
goto perform_seek_or_restore_command;
|
goto perform_seek_or_restore_command;
|
||||||
|
|
||||||
perform_step_command:
|
perform_step_command:
|
||||||
if(command_ & 0x10) goto adjust_track;
|
if(command_ & 0x10) goto adjust_track;
|
||||||
goto perform_step;
|
goto perform_step;
|
||||||
|
|
||||||
verify:
|
verify_seek:
|
||||||
|
update_status([this] (Status &status) {
|
||||||
|
status.track_zero = get_drive().get_is_track_zero();
|
||||||
|
});
|
||||||
if(!(command_ & 0x04)) {
|
if(!(command_ & 0x04)) {
|
||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,7 @@ class WD1770: public Storage::Disk::MFMController {
|
|||||||
bool data_request = false;
|
bool data_request = false;
|
||||||
bool interrupt_request = false;
|
bool interrupt_request = false;
|
||||||
bool busy = false;
|
bool busy = false;
|
||||||
|
bool track_zero = false;
|
||||||
enum {
|
enum {
|
||||||
One, Two, Three
|
One, Two, Three
|
||||||
} type = One;
|
} type = One;
|
||||||
|
@ -121,6 +121,7 @@ void DMAController::write(int address, uint16_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DMAController::set_floppy_drive_selection(bool drive1, bool drive2, bool side2) {
|
void DMAController::set_floppy_drive_selection(bool drive1, bool drive2, bool side2) {
|
||||||
|
// LOG("Selected: " << (drive1 ? "1" : "-") << (drive2 ? "2" : "-") << (side2 ? "s" : "-"));
|
||||||
fdc_.set_floppy_drive_selection(drive1, drive2, side2);
|
fdc_.set_floppy_drive_selection(drive1, drive2, side2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,11 +191,11 @@ int DMAController::bus_grant(uint16_t *ram, size_t size) {
|
|||||||
// Check that the older buffer is full; stop if not.
|
// Check that the older buffer is full; stop if not.
|
||||||
if(!buffer_[active_buffer_ ^ 1].is_full) return 0;
|
if(!buffer_[active_buffer_ ^ 1].is_full) return 0;
|
||||||
|
|
||||||
#define b(i, n) " " << PADHEX(2) << buffer_[i].contents[n]
|
#define b(i, n) " " << PADHEX(2) << int(buffer_[i].contents[n])
|
||||||
#define b2(i, n) b(i, n) << b(i, n+1)
|
#define b2(i, n) b(i, n) << b(i, n+1)
|
||||||
#define b4(i, n) b2(i, n) << b2(i, n+2)
|
#define b4(i, n) b2(i, n) << b2(i, n+2)
|
||||||
#define b16(i) b4(i, 0) << b4(i, 4) << b4(i, 8) << b4(i, 12)
|
#define b16(i) b4(i, 0) << b4(i, 4) << b4(i, 8) << b4(i, 12)
|
||||||
LOG("[1] to " << PADHEX(6) << address_ << b16(active_buffer_ ^ 1));
|
// LOG("[1] to " << PADHEX(6) << address_ << b16(active_buffer_ ^ 1));
|
||||||
|
|
||||||
for(int c = 0; c < 8; ++c) {
|
for(int c = 0; c < 8; ++c) {
|
||||||
if(size_t(address_) < size) {
|
if(size_t(address_) < size) {
|
||||||
@ -210,7 +211,7 @@ int DMAController::bus_grant(uint16_t *ram, size_t size) {
|
|||||||
// Check that the newer buffer is full; stop if not.
|
// Check that the newer buffer is full; stop if not.
|
||||||
if(!buffer_[active_buffer_ ].is_full) return 8;
|
if(!buffer_[active_buffer_ ].is_full) return 8;
|
||||||
|
|
||||||
LOG("[2] to " << PADHEX(6) << address_ << b16(active_buffer_));
|
// LOG("[2] to " << PADHEX(6) << address_ << b16(active_buffer_));
|
||||||
#undef b16
|
#undef b16
|
||||||
#undef b4
|
#undef b4
|
||||||
#undef b2
|
#undef b2
|
||||||
|
@ -63,7 +63,7 @@ void Drive::set_disk(const std::shared_ptr<Disk> &disk) {
|
|||||||
update_clocking_observer();
|
update_clocking_observer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drive::has_disk() {
|
bool Drive::has_disk() const {
|
||||||
return has_disk_;
|
return has_disk_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ ClockingHint::Preference Drive::preferred_clocking() {
|
|||||||
return (!motor_is_on_ || !has_disk_) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime;
|
return (!motor_is_on_ || !has_disk_) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drive::get_is_track_zero() {
|
bool Drive::get_is_track_zero() const {
|
||||||
return head_position_ == HeadPosition(0);
|
return head_position_ == HeadPosition(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,11 +114,11 @@ void Drive::set_head(int head) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Drive::get_head_count() {
|
int Drive::get_head_count() const {
|
||||||
return available_heads_;
|
return available_heads_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drive::get_tachometer() {
|
bool Drive::get_tachometer() const {
|
||||||
// I have made a guess here that the tachometer is a symmetric square wave;
|
// I have made a guess here that the tachometer is a symmetric square wave;
|
||||||
// if that is correct then around 60 beats per rotation appears to be correct
|
// if that is correct then around 60 beats per rotation appears to be correct
|
||||||
// to proceed beyond the speed checks I've so far uncovered.
|
// to proceed beyond the speed checks I've so far uncovered.
|
||||||
@ -126,22 +126,22 @@ bool Drive::get_tachometer() {
|
|||||||
return int(get_rotation() * 2.0f * ticks_per_rotation) & 1;
|
return int(get_rotation() * 2.0f * ticks_per_rotation) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Drive::get_rotation() {
|
float Drive::get_rotation() const {
|
||||||
return get_time_into_track();
|
return get_time_into_track();
|
||||||
}
|
}
|
||||||
|
|
||||||
float Drive::get_time_into_track() {
|
float Drive::get_time_into_track() const {
|
||||||
// i.e. amount of time since the index hole was seen, as a proportion of a second,
|
// i.e. amount of time since the index hole was seen, as a proportion of a second,
|
||||||
// converted to a proportion of a rotation.
|
// converted to a proportion of a rotation.
|
||||||
return float(cycles_since_index_hole_) / (float(get_input_clock_rate()) * rotational_multiplier_);
|
return float(cycles_since_index_hole_) / (float(get_input_clock_rate()) * rotational_multiplier_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drive::get_is_read_only() {
|
bool Drive::get_is_read_only() const {
|
||||||
if(disk_) return disk_->get_is_read_only();
|
if(disk_) return disk_->get_is_read_only();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drive::get_is_ready() {
|
bool Drive::get_is_ready() const {
|
||||||
return ready_index_count_ == 2;
|
return ready_index_count_ == 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,10 +164,14 @@ void Drive::set_motor_on(bool motor_is_on) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drive::get_motor_on() {
|
bool Drive::get_motor_on() const {
|
||||||
return motor_is_on_;
|
return motor_is_on_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Drive::get_index_pulse() const {
|
||||||
|
return index_pulse_remaining_ > Cycles(0);
|
||||||
|
}
|
||||||
|
|
||||||
void Drive::set_event_delegate(Storage::Disk::Drive::EventDelegate *delegate) {
|
void Drive::set_event_delegate(Storage::Disk::Drive::EventDelegate *delegate) {
|
||||||
event_delegate_ = delegate;
|
event_delegate_ = delegate;
|
||||||
}
|
}
|
||||||
@ -178,6 +182,9 @@ void Drive::advance(const Cycles cycles) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Drive::run_for(const Cycles cycles) {
|
void Drive::run_for(const Cycles cycles) {
|
||||||
|
// Assumed: the index pulse pulses even if the drive has stopped spinning.
|
||||||
|
index_pulse_remaining_ = std::max(index_pulse_remaining_ - cycles, Cycles(0));
|
||||||
|
|
||||||
if(motor_is_on_) {
|
if(motor_is_on_) {
|
||||||
if(has_disk_) {
|
if(has_disk_) {
|
||||||
Time zero(0);
|
Time zero(0);
|
||||||
@ -258,6 +265,11 @@ void Drive::get_next_event(float duration_already_passed) {
|
|||||||
current_event_.type = Track::Event::IndexHole;
|
current_event_.type = Track::Event::IndexHole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin a 2ms period of holding the index line pulse active if this is an index pulse event.
|
||||||
|
if(current_event_.type == Track::Event::IndexHole) {
|
||||||
|
index_pulse_remaining_ = Cycles((get_input_clock_rate() * 2) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
// divide interval, which is in terms of a single rotation of the disk, by rotation speed to
|
// divide interval, which is in terms of a single rotation of the disk, by rotation speed to
|
||||||
// convert it into revolutions per second; this is achieved by multiplying by rotational_multiplier_
|
// convert it into revolutions per second; this is achieved by multiplying by rotational_multiplier_
|
||||||
float interval = std::max((current_event_.length - duration_already_passed) * rotational_multiplier_, 0.0f);
|
float interval = std::max((current_event_.length - duration_already_passed) * rotational_multiplier_, 0.0f);
|
||||||
@ -384,7 +396,7 @@ void Drive::end_writing() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Drive::is_writing() {
|
bool Drive::is_writing() const {
|
||||||
return !is_reading_;
|
return !is_reading_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,12 +36,12 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
/*!
|
/*!
|
||||||
@returns @c true if a disk is currently inserted; @c false otherwise.
|
@returns @c true if a disk is currently inserted; @c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool has_disk();
|
bool has_disk() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns @c true if the drive head is currently at track zero; @c false otherwise.
|
@returns @c true if the drive head is currently at track zero; @c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool get_is_track_zero();
|
bool get_is_track_zero() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Steps the disk head the specified number of tracks. Positive numbers step inwards (i.e. away from track 0),
|
Steps the disk head the specified number of tracks. Positive numbers step inwards (i.e. away from track 0),
|
||||||
@ -57,17 +57,17 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
/*!
|
/*!
|
||||||
Gets the head count for this disk.
|
Gets the head count for this disk.
|
||||||
*/
|
*/
|
||||||
int get_head_count();
|
int get_head_count() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns @c true if the inserted disk is read-only or no disk is inserted; @c false otherwise.
|
@returns @c true if the inserted disk is read-only or no disk is inserted; @c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool get_is_read_only();
|
bool get_is_read_only() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns @c true if the drive is ready; @c false otherwise.
|
@returns @c true if the drive is ready; @c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool get_is_ready();
|
bool get_is_ready() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the disk motor is on.
|
Sets whether the disk motor is on.
|
||||||
@ -77,7 +77,12 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
/*!
|
/*!
|
||||||
@returns @c true if the motor is on; @c false otherwise.
|
@returns @c true if the motor is on; @c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool get_motor_on();
|
bool get_motor_on() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@returns @c true if the index pulse output is active; @c false otherwise.
|
||||||
|
*/
|
||||||
|
bool get_index_pulse() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Begins write mode, initiating a PCM sampled region of data. Bits should be written via
|
Begins write mode, initiating a PCM sampled region of data. Bits should be written via
|
||||||
@ -104,7 +109,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
@returns @c true if the drive has received a call to begin_writing but not yet a call to
|
@returns @c true if the drive has received a call to begin_writing but not yet a call to
|
||||||
end_writing; @c false otherwise.
|
end_writing; @c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool is_writing();
|
bool is_writing() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Advances the drive by @c number_of_cycles cycles.
|
Advances the drive by @c number_of_cycles cycles.
|
||||||
@ -163,7 +168,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
/*!
|
/*!
|
||||||
@returns the current value of the tachometer pulse offered by some drives.
|
@returns the current value of the tachometer pulse offered by some drives.
|
||||||
*/
|
*/
|
||||||
bool get_tachometer();
|
bool get_tachometer() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*!
|
/*!
|
||||||
@ -180,7 +185,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
@returns the current rotation of the disk, a float in the half-open range
|
@returns the current rotation of the disk, a float in the half-open range
|
||||||
0.0 (the index hole) to 1.0 (back to the index hole, a whole rotation later).
|
0.0 (the index hole) to 1.0 (back to the index hole, a whole rotation later).
|
||||||
*/
|
*/
|
||||||
float get_rotation();
|
float get_rotation() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Drives contain an entire disk; from that a certain track
|
// Drives contain an entire disk; from that a certain track
|
||||||
@ -210,6 +215,9 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
// Motor control state.
|
// Motor control state.
|
||||||
bool motor_is_on_ = false;
|
bool motor_is_on_ = false;
|
||||||
|
|
||||||
|
// Current state of the index pulse output.
|
||||||
|
Cycles index_pulse_remaining_;
|
||||||
|
|
||||||
// If the drive is not currently reading then it is writing. While writing
|
// If the drive is not currently reading then it is writing. While writing
|
||||||
// it can optionally be told to clamp to the index hole.
|
// it can optionally be told to clamp to the index hole.
|
||||||
bool is_reading_ = true;
|
bool is_reading_ = true;
|
||||||
@ -235,7 +243,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
void advance(const Cycles cycles) override;
|
void advance(const Cycles cycles) override;
|
||||||
|
|
||||||
// Helper for track changes.
|
// Helper for track changes.
|
||||||
float get_time_into_track();
|
float get_time_into_track() const;
|
||||||
|
|
||||||
// The target (if any) for track events.
|
// The target (if any) for track events.
|
||||||
EventDelegate *event_delegate_ = nullptr;
|
EventDelegate *event_delegate_ = nullptr;
|
||||||
|
@ -21,40 +21,40 @@ namespace Disk {
|
|||||||
class HeadPosition {
|
class HeadPosition {
|
||||||
public:
|
public:
|
||||||
/// Creates an instance decribing position @c value at a resolution of @c scale ticks per track.
|
/// Creates an instance decribing position @c value at a resolution of @c scale ticks per track.
|
||||||
HeadPosition(int value, int scale) : position_(value * (4/scale)) {}
|
constexpr HeadPosition(int value, int scale) : position_(value * (4/scale)) {}
|
||||||
explicit HeadPosition(int value) : HeadPosition(value, 1) {}
|
constexpr explicit HeadPosition(int value) : HeadPosition(value, 1) {}
|
||||||
HeadPosition() : HeadPosition(0) {}
|
constexpr HeadPosition() : HeadPosition(0) {}
|
||||||
|
|
||||||
/// @returns the whole number part of the position.
|
/// @returns the whole number part of the position.
|
||||||
int as_int() const { return position_ >> 2; }
|
constexpr int as_int() const { return position_ >> 2; }
|
||||||
/// @returns n where n/2 is the head position.
|
/// @returns n where n/2 is the head position.
|
||||||
int as_half() const { return position_ >> 1; }
|
constexpr int as_half() const { return position_ >> 1; }
|
||||||
/// @returns n where n/4 is the head position.
|
/// @returns n where n/4 is the head position.
|
||||||
int as_quarter() const { return position_; }
|
constexpr int as_quarter() const { return position_; }
|
||||||
|
|
||||||
/// @returns the head position at maximal but unspecified precision.
|
/// @returns the head position at maximal but unspecified precision.
|
||||||
int as_largest() const { return as_quarter(); }
|
constexpr int as_largest() const { return as_quarter(); }
|
||||||
|
|
||||||
HeadPosition &operator +=(const HeadPosition &rhs) {
|
HeadPosition &operator +=(const HeadPosition &rhs) {
|
||||||
position_ += rhs.position_;
|
position_ += rhs.position_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
bool operator ==(const HeadPosition &rhs) const {
|
constexpr bool operator ==(const HeadPosition &rhs) const {
|
||||||
return position_ == rhs.position_;
|
return position_ == rhs.position_;
|
||||||
}
|
}
|
||||||
bool operator !=(const HeadPosition &rhs) const {
|
constexpr bool operator !=(const HeadPosition &rhs) const {
|
||||||
return position_ != rhs.position_;
|
return position_ != rhs.position_;
|
||||||
}
|
}
|
||||||
bool operator <(const HeadPosition &rhs) const {
|
constexpr bool operator <(const HeadPosition &rhs) const {
|
||||||
return position_ < rhs.position_;
|
return position_ < rhs.position_;
|
||||||
}
|
}
|
||||||
bool operator <=(const HeadPosition &rhs) const {
|
constexpr bool operator <=(const HeadPosition &rhs) const {
|
||||||
return position_ <= rhs.position_;
|
return position_ <= rhs.position_;
|
||||||
}
|
}
|
||||||
bool operator >(const HeadPosition &rhs) const {
|
constexpr bool operator >(const HeadPosition &rhs) const {
|
||||||
return position_ > rhs.position_;
|
return position_ > rhs.position_;
|
||||||
}
|
}
|
||||||
bool operator >=(const HeadPosition &rhs) const {
|
constexpr bool operator >=(const HeadPosition &rhs) const {
|
||||||
return position_ >= rhs.position_;
|
return position_ >= rhs.position_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ class Track {
|
|||||||
int head;
|
int head;
|
||||||
HeadPosition position;
|
HeadPosition position;
|
||||||
|
|
||||||
bool operator < (const Address &rhs) const {
|
constexpr bool operator < (const Address &rhs) const {
|
||||||
int largest_position = position.as_largest();
|
int largest_position = position.as_largest();
|
||||||
int rhs_largest_position = rhs.position.as_largest();
|
int rhs_largest_position = rhs.position.as_largest();
|
||||||
return std::tie(head, largest_position) < std::tie(rhs.head, rhs_largest_position);
|
return std::tie(head, largest_position) < std::tie(rhs.head, rhs_largest_position);
|
||||||
|
@ -46,11 +46,11 @@ void TimedEventLoop::run_for(const Cycles cycles) {
|
|||||||
assert(cycles_until_event_ > 0);
|
assert(cycles_until_event_ > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cycles::IntType TimedEventLoop::get_cycles_until_next_event() {
|
Cycles::IntType TimedEventLoop::get_cycles_until_next_event() const {
|
||||||
return std::max(cycles_until_event_, Cycles::IntType(0));
|
return std::max(cycles_until_event_, Cycles::IntType(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Cycles::IntType TimedEventLoop::get_input_clock_rate() {
|
Cycles::IntType TimedEventLoop::get_input_clock_rate() const {
|
||||||
return input_clock_rate_;
|
return input_clock_rate_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +52,12 @@ namespace Storage {
|
|||||||
/*!
|
/*!
|
||||||
@returns the number of whole cycles remaining until the next event is triggered.
|
@returns the number of whole cycles remaining until the next event is triggered.
|
||||||
*/
|
*/
|
||||||
Cycles::IntType get_cycles_until_next_event();
|
Cycles::IntType get_cycles_until_next_event() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns the input clock rate.
|
@returns the input clock rate.
|
||||||
*/
|
*/
|
||||||
Cycles::IntType get_input_clock_rate();
|
Cycles::IntType get_input_clock_rate() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*!
|
/*!
|
||||||
|
Loading…
Reference in New Issue
Block a user