mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Merge pull request #636 from TomHarte/PWM
Attempts more accurately to match Apple's IWM windowing logic.
This commit is contained in:
commit
917520fb1e
@ -235,23 +235,32 @@ void IWM::run_for(const Cycles cycles) {
|
|||||||
// Activity otherwise depends on mode and motor state.
|
// Activity otherwise depends on mode and motor state.
|
||||||
int integer_cycles = cycles.as_int();
|
int integer_cycles = cycles.as_int();
|
||||||
switch(shift_mode_) {
|
switch(shift_mode_) {
|
||||||
case ShiftMode::Reading:
|
case ShiftMode::Reading: {
|
||||||
|
// Per the IWM patent, column 7, around line 35 onwards: "The expected time
|
||||||
|
// is widened by approximately one-half an interval before and after the
|
||||||
|
// expected time since the data is not precisely spaced when read due to
|
||||||
|
// variations in drive speed and other external factors". The error_margin
|
||||||
|
// here implements the 'after' part of that contract.
|
||||||
|
const auto error_margin = Cycles(bit_length_.as_int() >> 1);
|
||||||
|
|
||||||
if(drive_is_rotating_[active_drive_]) {
|
if(drive_is_rotating_[active_drive_]) {
|
||||||
while(integer_cycles--) {
|
while(integer_cycles--) {
|
||||||
drives_[active_drive_]->run_for(Cycles(1));
|
drives_[active_drive_]->run_for(Cycles(1));
|
||||||
++cycles_since_shift_;
|
++cycles_since_shift_;
|
||||||
if(cycles_since_shift_ == bit_length_ + Cycles(2)) {
|
if(cycles_since_shift_ == bit_length_ + error_margin) {
|
||||||
propose_shift(0);
|
propose_shift(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while(cycles_since_shift_ + integer_cycles >= bit_length_ + Cycles(2)) {
|
while(cycles_since_shift_ + integer_cycles >= bit_length_ + error_margin) {
|
||||||
|
const auto run_length = bit_length_ + error_margin - cycles_since_shift_;
|
||||||
|
integer_cycles -= run_length.as_int();
|
||||||
|
cycles_since_shift_ += run_length;
|
||||||
propose_shift(0);
|
propose_shift(0);
|
||||||
integer_cycles -= bit_length_.as_int() + 2 - cycles_since_shift_.as_int();
|
|
||||||
}
|
}
|
||||||
cycles_since_shift_ += Cycles(integer_cycles);
|
cycles_since_shift_ += Cycles(integer_cycles);
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
|
|
||||||
case ShiftMode::Writing:
|
case ShiftMode::Writing:
|
||||||
if(drives_[active_drive_]->is_writing()) {
|
if(drives_[active_drive_]->is_writing()) {
|
||||||
@ -351,12 +360,28 @@ void IWM::propose_shift(uint8_t bit) {
|
|||||||
// TODO: synchronous mode.
|
// TODO: synchronous mode.
|
||||||
|
|
||||||
// LOG("Shifting input");
|
// LOG("Shifting input");
|
||||||
|
|
||||||
|
// See above for text from the IWM patent, column 7, around line 35 onwards.
|
||||||
|
// The error_margin here implements the 'before' part of that contract.
|
||||||
|
//
|
||||||
|
// Basic effective logic: if at least 1 is fozund in the bit_length_ cycles centred
|
||||||
|
// on the current expected bit delivery time as implied by cycles_since_shift_,
|
||||||
|
// shift in a 1 and start a new window wherever the first found 1 was.
|
||||||
|
//
|
||||||
|
// If no 1s are found, shift in a 0 and don't alter expectations as to window placement.
|
||||||
|
const auto error_margin = Cycles(bit_length_.as_int() >> 1);
|
||||||
|
if(bit && cycles_since_shift_ < error_margin) return;
|
||||||
|
|
||||||
shift_register_ = uint8_t((shift_register_ << 1) | bit);
|
shift_register_ = uint8_t((shift_register_ << 1) | bit);
|
||||||
if(shift_register_ & 0x80) {
|
if(shift_register_ & 0x80) {
|
||||||
data_register_ = shift_register_;
|
data_register_ = shift_register_;
|
||||||
shift_register_ = 0;
|
shift_register_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(bit)
|
||||||
cycles_since_shift_ = Cycles(0);
|
cycles_since_shift_ = Cycles(0);
|
||||||
|
else
|
||||||
|
cycles_since_shift_ -= bit_length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IWM::set_drive(int slot, IWMDrive *drive) {
|
void IWM::set_drive(int slot, IWMDrive *drive) {
|
||||||
|
Loading…
Reference in New Issue
Block a user