mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 03:32:32 +00:00
Implements the ugly stuff of converting a DMK back to flux.
This commit is contained in:
parent
4ef583813a
commit
aafdff49be
@ -8,8 +8,30 @@
|
||||
|
||||
#include "DMK.hpp"
|
||||
|
||||
#include "../../Encodings/MFM/Constants.hpp"
|
||||
#include "../../Encodings/MFM/Encoder.hpp"
|
||||
#include "../../Track/PCMTrack.hpp"
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
namespace {
|
||||
|
||||
std::unique_ptr<Storage::Encodings::MFM::Encoder> new_encoder(Storage::Disk::PCMSegment &segment, bool is_double_density) {
|
||||
std::unique_ptr<Storage::Encodings::MFM::Encoder> encoder;
|
||||
|
||||
if(is_double_density) {
|
||||
encoder = Storage::Encodings::MFM::GetMFMEncoder(segment.data);
|
||||
segment.length_of_a_bit = Storage::Encodings::MFM::MFMBitLength;
|
||||
} else {
|
||||
encoder = Storage::Encodings::MFM::GetFMEncoder(segment.data);
|
||||
segment.length_of_a_bit = Storage::Encodings::MFM::FMBitLength;
|
||||
}
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DMK::DMK(const char *file_name) :
|
||||
file_(file_name) {
|
||||
// Determine whether this DMK represents a read-only disk (whether intentionally,
|
||||
@ -48,7 +70,9 @@ int DMK::get_head_count() {
|
||||
}
|
||||
|
||||
bool DMK::get_is_read_only() {
|
||||
return is_read_only_;
|
||||
return true;
|
||||
// Given that track serialisation is not yet implemented, treat all DMKs as read-only.
|
||||
// return is_read_only_;
|
||||
}
|
||||
|
||||
long DMK::get_file_offset_for_position(Track::Address address) {
|
||||
@ -58,18 +82,107 @@ long DMK::get_file_offset_for_position(Track::Address address) {
|
||||
std::shared_ptr<::Storage::Disk::Track> DMK::get_track_at_position(::Storage::Disk::Track::Address address) {
|
||||
file_.seek(get_file_offset_for_position(address), SEEK_SET);
|
||||
|
||||
// Read the IDAM table.
|
||||
uint16_t idam_locations[64];
|
||||
std::size_t index = 0;
|
||||
for(std::size_t c = 0; c < sizeof(idam_locations); ++c) {
|
||||
idam_locations[index] = file_.get16le();
|
||||
if((idam_locations[index] & 0x7fff) >= 128) {
|
||||
index++;
|
||||
std::size_t idam_count = 0;
|
||||
for(std::size_t c = 0; c < sizeof(idam_locations) / sizeof(*idam_locations); ++c) {
|
||||
idam_locations[idam_count] = file_.get16le();
|
||||
if((idam_locations[idam_count] & 0x7fff) >= 128) {
|
||||
idam_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// `index` is now the final (sensical) entry in the IDAM location table.
|
||||
// TODO: parse track contents.
|
||||
printf("number of IDAMs: %d", index);
|
||||
// Grab the rest of the track.
|
||||
std::vector<uint8_t> track = file_.read(static_cast<std::size_t>(track_length_ - 0x80));
|
||||
|
||||
return nullptr;
|
||||
// Default to outputting double density unless the disk doesn't support it.
|
||||
bool is_double_density = !is_purely_single_density_;
|
||||
std::vector<PCMSegment> segments;
|
||||
std::unique_ptr<Encodings::MFM::Encoder> encoder;
|
||||
segments.emplace_back();
|
||||
encoder = new_encoder(segments.back(), is_double_density);
|
||||
|
||||
std::size_t idam_pointer = 0;
|
||||
|
||||
const std::size_t track_length = static_cast<std::size_t>(track_length_) - 0x80;
|
||||
std::size_t track_pointer = 0;
|
||||
while(track_pointer < track_length) {
|
||||
// Determine bytes left until next IDAM.
|
||||
std::size_t destination;
|
||||
if(idam_pointer != idam_count) {
|
||||
destination = (idam_locations[idam_pointer] & 0x7fff) - 0x80;
|
||||
} else {
|
||||
destination = track_length;
|
||||
}
|
||||
|
||||
// Output every intermediate byte.
|
||||
if(!is_double_density && !is_purely_single_density_) {
|
||||
is_double_density = true;
|
||||
segments.emplace_back();
|
||||
encoder = new_encoder(segments.back(), is_double_density);
|
||||
}
|
||||
while(track_pointer < destination) {
|
||||
encoder->add_byte(track[track_pointer]);
|
||||
track_pointer++;
|
||||
}
|
||||
|
||||
// Exit now if that's it.
|
||||
if(destination == track_length) break;
|
||||
|
||||
// Being now located at the IDAM, check for a change of encoding.
|
||||
bool next_is_double_density = !!(idam_locations[idam_pointer] & 0x8000);
|
||||
if(next_is_double_density != is_double_density) {
|
||||
is_double_density = next_is_double_density;
|
||||
segments.emplace_back();
|
||||
encoder = new_encoder(segments.back(), is_double_density);
|
||||
}
|
||||
|
||||
// Now at the IDAM, which will always be an FE regardless of FM/MFM encoding,
|
||||
// presumably through misunderstanding of the designer? Write out a real IDAM
|
||||
// for the current density, then the rest of the ID — four bytes for the address
|
||||
// plus two for the CRC. Keep a copy of the header while we're here, so that the
|
||||
// size of the sector is known momentarily.
|
||||
std::size_t step_rate = (!is_double_density && !is_purely_single_density_) ? 2 : 1;
|
||||
encoder->add_ID_address_mark();
|
||||
uint8_t header[6];
|
||||
for(int c = 0; c < 6; ++c) {
|
||||
track_pointer += step_rate;
|
||||
encoder->add_byte(track[track_pointer]);
|
||||
header[c] = track[track_pointer];
|
||||
}
|
||||
track_pointer += step_rate;
|
||||
|
||||
// Now write out as many bytes as are found prior to an FB or F8 (same comment as
|
||||
// above: those are the FM-esque marks, but it seems as though transcription to MFM
|
||||
// is implicit).
|
||||
while(true) {
|
||||
uint8_t next_byte = track[track_pointer];
|
||||
track_pointer += step_rate;
|
||||
if(next_byte == 0xfb || next_byte == 0xf8) {
|
||||
// Write a data or deleted data address mark.
|
||||
if(next_byte == 0xfb) encoder->add_data_address_mark();
|
||||
else encoder->add_deleted_data_address_mark();
|
||||
break;
|
||||
}
|
||||
encoder->add_byte(next_byte);
|
||||
}
|
||||
|
||||
// Now write out a data mark (the file format appears to leave these implicit?),
|
||||
// then the sector contents plus the CRC.
|
||||
encoder->add_data_address_mark();
|
||||
int sector_size = 2 + (128 << header[3]);
|
||||
while(sector_size--) {
|
||||
encoder->add_byte(track[track_pointer]);
|
||||
track_pointer += step_rate;
|
||||
}
|
||||
|
||||
idam_pointer++;
|
||||
}
|
||||
|
||||
// All segments should be exactly their number of bits in length.
|
||||
for(auto &segment : segments) {
|
||||
segment.number_of_bits = static_cast<unsigned int>(segment.data.size() * 8);
|
||||
}
|
||||
|
||||
return std::make_shared<PCMTrack>(segments);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user