mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-29 00:29:28 +00:00
Merge pull request #733 from TomHarte/STXTiming
Adds support for STX speed zones.
This commit is contained in:
commit
f02759b76b
@ -201,7 +201,7 @@ class TrackConstructor {
|
|||||||
// Otherwise, seek to encode the sectors, using the track data to
|
// Otherwise, seek to encode the sectors, using the track data to
|
||||||
// fill in the gaps (if provided).
|
// fill in the gaps (if provided).
|
||||||
std::unique_ptr<Storage::Encodings::MFM::Encoder> encoder;
|
std::unique_ptr<Storage::Encodings::MFM::Encoder> encoder;
|
||||||
std::unique_ptr<PCMSegment> segment;
|
std::vector<PCMSegment> segments;
|
||||||
|
|
||||||
// To reconcile the list of sectors with the WD get track-style track image,
|
// To reconcile the list of sectors with the WD get track-style track image,
|
||||||
// use sector bodies as definitive and refer to the track image for in-fill.
|
// use sector bodies as definitive and refer to the track image for in-fill.
|
||||||
@ -256,11 +256,18 @@ class TrackConstructor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just create an encoder if one doesn't exist. TODO: factor in data rate.
|
const auto encoder_at_rate = [&encoder, &segments](unsigned int rate) -> Storage::Encodings::MFM::Encoder* {
|
||||||
if(!encoder) {
|
if(!encoder) {
|
||||||
segment.reset(new PCMSegment);
|
segments.emplace_back();
|
||||||
encoder = Storage::Encodings::MFM::GetMFMEncoder(segment->data);
|
segments.back().length_of_a_bit = Storage::Time(int(rate), 1);
|
||||||
}
|
encoder = Storage::Encodings::MFM::GetMFMEncoder(segments.back().data);
|
||||||
|
} else if(segments.back().length_of_a_bit.length != rate) {
|
||||||
|
segments.emplace_back();
|
||||||
|
segments.back().length_of_a_bit = Storage::Time(int(rate), 1);
|
||||||
|
encoder->reset_target(segments.back().data);
|
||||||
|
}
|
||||||
|
return encoder.get();
|
||||||
|
};
|
||||||
|
|
||||||
// Write out, being wary of potential overlapping sectors, and copying from track_data_ to fill in gaps.
|
// Write out, being wary of potential overlapping sectors, and copying from track_data_ to fill in gaps.
|
||||||
auto location = locations.begin();
|
auto location = locations.begin();
|
||||||
@ -269,8 +276,9 @@ class TrackConstructor {
|
|||||||
// assert(location->position >= track_position && location->position < track_data_.end());
|
// assert(location->position >= track_position && location->position < track_data_.end());
|
||||||
|
|
||||||
// Advance to location.position.
|
// Advance to location.position.
|
||||||
|
auto default_rate_encoder = encoder_at_rate(128);
|
||||||
while(track_position < location->position) {
|
while(track_position < location->position) {
|
||||||
encoder->add_byte(*track_position);
|
default_rate_encoder->add_byte(*track_position);
|
||||||
++track_position;
|
++track_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,14 +287,14 @@ class TrackConstructor {
|
|||||||
switch(location->type) {
|
switch(location->type) {
|
||||||
default:
|
default:
|
||||||
case Location::Address:
|
case Location::Address:
|
||||||
encoder->add_ID_address_mark();
|
default_rate_encoder->add_ID_address_mark();
|
||||||
bytes_to_write = 6;
|
bytes_to_write = 6;
|
||||||
break;
|
break;
|
||||||
case Location::Data:
|
case Location::Data:
|
||||||
if(location->sector.status & 0x20)
|
if(location->sector.status & 0x20)
|
||||||
encoder->add_deleted_data_address_mark();
|
default_rate_encoder->add_deleted_data_address_mark();
|
||||||
else
|
else
|
||||||
encoder->add_data_address_mark();
|
default_rate_encoder->add_data_address_mark();
|
||||||
bytes_to_write = location->sector.data_size() + 2;
|
bytes_to_write = location->sector.data_size() + 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -306,16 +314,27 @@ class TrackConstructor {
|
|||||||
default:
|
default:
|
||||||
case Location::Address:
|
case Location::Address:
|
||||||
for(size_t c = 0; c < bytes_to_write; ++c)
|
for(size_t c = 0; c < bytes_to_write; ++c)
|
||||||
encoder->add_byte(location->sector.address[c]);
|
default_rate_encoder->add_byte(location->sector.address[c]);
|
||||||
break;
|
break;
|
||||||
case Location::Data: {
|
case Location::Data: {
|
||||||
const auto body_bytes = std::min(bytes_to_write, size_t(location->sector.data_size()));
|
const auto body_bytes = std::min(bytes_to_write, size_t(location->sector.data_size()));
|
||||||
for(size_t c = 0; c < body_bytes; ++c)
|
|
||||||
encoder->add_byte(location->sector.contents[c]);
|
// If timing information is attached to this sector, write each byte at the proper speed.
|
||||||
|
// (TODO: is there any benefit to optiming number of calls to encoder_at_rate?)
|
||||||
|
if(!location->sector.timing.empty()) {
|
||||||
|
for(size_t c = 0; c < body_bytes; ++c) {
|
||||||
|
encoder_at_rate(location->sector.timing[c >> 4])->add_byte(location->sector.contents[c]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(size_t c = 0; c < body_bytes; ++c) {
|
||||||
|
default_rate_encoder->add_byte(location->sector.contents[c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add a CRC only if it fits (TODO: crop if necessary?).
|
// Add a CRC only if it fits (TODO: crop if necessary?).
|
||||||
if(bytes_to_write & 127) {
|
if(bytes_to_write & 127) {
|
||||||
encoder->add_crc((location->sector.status & 0x18) == 0x10);
|
default_rate_encoder = encoder_at_rate(128);
|
||||||
|
default_rate_encoder->add_crc((location->sector.status & 0x18) == 0x10);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -330,20 +349,28 @@ class TrackConstructor {
|
|||||||
++track_position;
|
++track_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Count total size of track.
|
||||||
|
size_t track_size = 0;
|
||||||
|
for(auto &segment: segments) {
|
||||||
|
track_size += segment.data.size();
|
||||||
|
}
|
||||||
|
|
||||||
// Write generic padding up until the specified track size.
|
// Write generic padding up until the specified track size.
|
||||||
while(segment->data.size() < track_size_ * 16) {
|
while(track_size < track_size_ * 16) {
|
||||||
encoder->add_byte(0x4e);
|
encoder->add_byte(0x4e);
|
||||||
|
track_size += 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad out to the minimum size a WD can actually make sense of.
|
// Pad out to the minimum size a WD can actually make sense of.
|
||||||
// I've no idea why it's valid for tracks to be shorter than this,
|
// I've no idea why it's valid for tracks to be shorter than this,
|
||||||
// so likely I'm suffering a comprehansion deficiency.
|
// so likely I'm suffering a comprehansion deficiency.
|
||||||
// TODO: determine why this isn't correct (or, possibly, is).
|
// TODO: determine why this isn't correct (or, possibly, is).
|
||||||
while(segment->data.size() < 5750 * 16) {
|
while(track_size < 5750 * 16) {
|
||||||
encoder->add_byte(0x4e);
|
encoder->add_byte(0x4e);
|
||||||
|
track_size += 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<PCMTrack>(*segment);
|
return std::make_shared<PCMTrack>(segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -241,12 +241,16 @@ template<class T> std::shared_ptr<Storage::Disk::Track>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Encoder::Encoder(std::vector<bool> &target) :
|
Encoder::Encoder(std::vector<bool> &target) :
|
||||||
target_(target) {}
|
target_(&target) {}
|
||||||
|
|
||||||
|
void Encoder::reset_target(std::vector<bool> &target) {
|
||||||
|
target_ = ⌖
|
||||||
|
}
|
||||||
|
|
||||||
void Encoder::output_short(uint16_t value) {
|
void Encoder::output_short(uint16_t value) {
|
||||||
uint16_t mask = 0x8000;
|
uint16_t mask = 0x8000;
|
||||||
while(mask) {
|
while(mask) {
|
||||||
target_.push_back(!!(value & mask));
|
target_->push_back(!!(value & mask));
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,8 @@ class Encoder {
|
|||||||
public:
|
public:
|
||||||
Encoder(std::vector<bool> &target);
|
Encoder(std::vector<bool> &target);
|
||||||
virtual ~Encoder() {}
|
virtual ~Encoder() {}
|
||||||
|
virtual void reset_target(std::vector<bool> &target);
|
||||||
|
|
||||||
virtual void add_byte(uint8_t input) = 0;
|
virtual void add_byte(uint8_t input) = 0;
|
||||||
virtual void add_index_address_mark() = 0;
|
virtual void add_index_address_mark() = 0;
|
||||||
virtual void add_ID_address_mark() = 0;
|
virtual void add_ID_address_mark() = 0;
|
||||||
@ -60,7 +62,7 @@ class Encoder {
|
|||||||
CRC::CCITT crc_generator_;
|
CRC::CCITT crc_generator_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<bool> &target_;
|
std::vector<bool> *target_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Encoder> GetMFMEncoder(std::vector<bool> &target);
|
std::unique_ptr<Encoder> GetMFMEncoder(std::vector<bool> &target);
|
||||||
|
Loading…
Reference in New Issue
Block a user