mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Makes a first attempt at six-and-two encoding for DSKs.
This commit is contained in:
parent
b98d5b790a
commit
7f03f5d02f
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include "AppleDSK.hpp"
|
#include "AppleDSK.hpp"
|
||||||
|
|
||||||
|
#include "../../Track/PCMTrack.hpp"
|
||||||
|
#include "../../Encodings/AppleGCR.hpp"
|
||||||
|
|
||||||
using namespace Storage::Disk;
|
using namespace Storage::Disk;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -30,8 +33,29 @@ int AppleDSK::get_head_position_count() {
|
|||||||
std::shared_ptr<Track> AppleDSK::get_track_at_position(Track::Address address) {
|
std::shared_ptr<Track> AppleDSK::get_track_at_position(Track::Address address) {
|
||||||
const long file_offset = (address.position >> 2) * bytes_per_sector * sectors_per_track_;
|
const long file_offset = (address.position >> 2) * bytes_per_sector * sectors_per_track_;
|
||||||
file_.seek(file_offset, SEEK_SET);
|
file_.seek(file_offset, SEEK_SET);
|
||||||
|
const std::vector<uint8_t> track_data = file_.read(static_cast<size_t>(bytes_per_sector * sectors_per_track_));
|
||||||
|
|
||||||
// std::vector<uint8_t> track_data = file_.read(bytes_per_sector * sectors_per_track_);
|
std::vector<Storage::Disk::PCMSegment> segments;
|
||||||
|
const uint8_t track = static_cast<uint8_t>(address.position >> 2);
|
||||||
|
|
||||||
return nullptr;
|
// In either case below, the code aims for exactly 50,000 bits per track.
|
||||||
|
if(sectors_per_track_ == 16) {
|
||||||
|
|
||||||
|
// Write the sectors.
|
||||||
|
for(uint8_t c = 0; c < 16; ++c) {
|
||||||
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync(10));
|
||||||
|
segments.push_back(Encodings::AppleGCR::header(0, track, c));
|
||||||
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync(10));
|
||||||
|
segments.push_back(Encodings::AppleGCR::six_and_two_data(&track_data[c * 256]));
|
||||||
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
int encoded_length = (80 + 112 + 80 + 2848 + 80) * sectors_per_track_;
|
||||||
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync((50000 - encoded_length) >> 3));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::shared_ptr<PCMTrack>(new PCMTrack(segments));
|
||||||
}
|
}
|
||||||
|
@ -8,55 +8,31 @@
|
|||||||
|
|
||||||
#include "AppleGCR.hpp"
|
#include "AppleGCR.hpp"
|
||||||
|
|
||||||
using namespace Storage::Encodings;
|
namespace {
|
||||||
|
|
||||||
unsigned int AppleGCR::five_and_three_encoding_for_value(int value) {
|
const unsigned int five_and_three_mapping[] = {
|
||||||
static const unsigned int values[] = {
|
0xab, 0xad, 0xae, 0xaf, 0xb5, 0xb6, 0xb7, 0xba,
|
||||||
0xab, 0xad, 0xae, 0xaf, 0xb5, 0xb6, 0xb7, 0xba,
|
0xbb, 0xbd, 0xbe, 0xbf, 0xd6, 0xd7, 0xda, 0xdb,
|
||||||
0xbb, 0xbd, 0xbe, 0xbf, 0xd6, 0xd7, 0xda, 0xdb,
|
0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xed, 0xee, 0xef,
|
||||||
0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xed, 0xee, 0xef,
|
0xf5, 0xf6, 0xf7, 0xfa, 0xfb, 0xfd, 0xfe, 0xff
|
||||||
0xf5, 0xf6, 0xf7, 0xfa, 0xfb, 0xfd, 0xfe, 0xff
|
};
|
||||||
};
|
|
||||||
return values[value & 0x1f];
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppleGCR::encode_five_and_three_block(uint8_t *destination, uint8_t *source) {
|
const uint8_t six_and_two_mapping[] = {
|
||||||
destination[0] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[0] >> 3 ));
|
0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
|
||||||
destination[1] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[0] << 2) | (source[1] >> 6) ));
|
0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
|
||||||
destination[2] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[1] >> 1 ));
|
0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc,
|
||||||
destination[3] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[1] << 4) | (source[2] >> 4) ));
|
0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3,
|
||||||
destination[4] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[2] << 1) | (source[3] >> 7) ));
|
0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
|
||||||
destination[5] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[3] >> 2 ));
|
0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec,
|
||||||
destination[6] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[3] << 3) | (source[4] >> 5) ));
|
0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
|
||||||
destination[7] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[4] ));
|
0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||||
}
|
};
|
||||||
|
|
||||||
unsigned int AppleGCR::six_and_two_encoding_for_value(int value) {
|
|
||||||
static const unsigned int values[] = {
|
|
||||||
0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
|
|
||||||
0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
|
|
||||||
0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc,
|
|
||||||
0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3,
|
|
||||||
0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
|
|
||||||
0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec,
|
|
||||||
0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
|
|
||||||
0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
|
||||||
};
|
|
||||||
return values[value & 0x3f];
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppleGCR::encode_six_and_two_block(uint8_t *destination, uint8_t *source) {
|
|
||||||
destination[0] = static_cast<uint8_t>(six_and_two_encoding_for_value( source[0] >> 2 ));
|
|
||||||
destination[1] = static_cast<uint8_t>(six_and_two_encoding_for_value( (source[0] << 4) | (source[1] >> 4) ));
|
|
||||||
destination[2] = static_cast<uint8_t>(six_and_two_encoding_for_value( (source[1] << 2) | (source[2] >> 6) ));
|
|
||||||
destination[3] = static_cast<uint8_t>(six_and_two_encoding_for_value( source[2] ));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Produces a PCM segment containing @c length sync bytes, each aligned to the beginning of
|
Produces a PCM segment containing @c length sync bytes, each aligned to the beginning of
|
||||||
a @c bit_size -sized window.
|
a @c bit_size -sized window.
|
||||||
*/
|
*/
|
||||||
static Storage::Disk::PCMSegment sync(int length, int bit_size) {
|
Storage::Disk::PCMSegment sync(int length, int bit_size) {
|
||||||
Storage::Disk::PCMSegment segment;
|
Storage::Disk::PCMSegment segment;
|
||||||
|
|
||||||
// Allocate sufficient storage.
|
// Allocate sufficient storage.
|
||||||
@ -73,6 +49,30 @@ static Storage::Disk::PCMSegment sync(int length, int bit_size) {
|
|||||||
return segment;
|
return segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Storage::Encodings;
|
||||||
|
|
||||||
|
|
||||||
|
/*void AppleGCR::encode_five_and_three_block(uint8_t *destination, uint8_t *source) {
|
||||||
|
destination[0] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[0] >> 3 ));
|
||||||
|
destination[1] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[0] << 2) | (source[1] >> 6) ));
|
||||||
|
destination[2] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[1] >> 1 ));
|
||||||
|
destination[3] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[1] << 4) | (source[2] >> 4) ));
|
||||||
|
destination[4] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[2] << 1) | (source[3] >> 7) ));
|
||||||
|
destination[5] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[3] >> 2 ));
|
||||||
|
destination[6] = static_cast<uint8_t>(five_and_three_encoding_for_value( (source[3] << 3) | (source[4] >> 5) ));
|
||||||
|
destination[7] = static_cast<uint8_t>(five_and_three_encoding_for_value( source[4] ));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
/*void AppleGCR::encode_six_and_two_block(uint8_t *destination, uint8_t *source) {
|
||||||
|
destination[0] = static_cast<uint8_t>(six_and_two_encoding_for_value( source[0] >> 2 ));
|
||||||
|
destination[1] = static_cast<uint8_t>(six_and_two_encoding_for_value( (source[0] << 4) | (source[1] >> 4) ));
|
||||||
|
destination[2] = static_cast<uint8_t>(six_and_two_encoding_for_value( (source[1] << 2) | (source[2] >> 6) ));
|
||||||
|
destination[3] = static_cast<uint8_t>(six_and_two_encoding_for_value( source[2] ));
|
||||||
|
}*/
|
||||||
|
|
||||||
Storage::Disk::PCMSegment AppleGCR::six_and_two_sync(int length) {
|
Storage::Disk::PCMSegment AppleGCR::six_and_two_sync(int length) {
|
||||||
return sync(length, 9);
|
return sync(length, 9);
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ Storage::Disk::PCMSegment AppleGCR::header(uint8_t volume, uint8_t track, uint8_
|
|||||||
return segment;
|
return segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage::Disk::PCMSegment AppleGCR::five_and_three_data(uint8_t *source) {
|
Storage::Disk::PCMSegment AppleGCR::five_and_three_data(const uint8_t *source) {
|
||||||
Storage::Disk::PCMSegment segment;
|
Storage::Disk::PCMSegment segment;
|
||||||
|
|
||||||
segment.data.resize(410 + 7);
|
segment.data.resize(410 + 7);
|
||||||
@ -119,25 +119,63 @@ Storage::Disk::PCMSegment AppleGCR::five_and_three_data(uint8_t *source) {
|
|||||||
segment.data[1] = header_prologue[1];
|
segment.data[1] = header_prologue[1];
|
||||||
segment.data[2] = header_prologue[2];
|
segment.data[2] = header_prologue[2];
|
||||||
|
|
||||||
std::size_t source_pointer = 0;
|
// std::size_t source_pointer = 0;
|
||||||
std::size_t destination_pointer = 3;
|
// std::size_t destination_pointer = 3;
|
||||||
while(source_pointer < 255) {
|
// while(source_pointer < 255) {
|
||||||
encode_five_and_three_block(&segment.data[destination_pointer], &source[source_pointer]);
|
// encode_five_and_three_block(&segment.data[destination_pointer], &source[source_pointer]);
|
||||||
|
//
|
||||||
source_pointer += 5;
|
// source_pointer += 5;
|
||||||
destination_pointer += 8;
|
// destination_pointer += 8;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return segment;
|
return segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage::Disk::PCMSegment AppleGCR::six_and_two_data(uint8_t *source) {
|
Storage::Disk::PCMSegment AppleGCR::six_and_two_data(const uint8_t *source) {
|
||||||
Storage::Disk::PCMSegment segment;
|
Storage::Disk::PCMSegment segment;
|
||||||
|
|
||||||
segment.data.resize(342 + 7);
|
segment.data.resize(349);
|
||||||
|
|
||||||
|
// Add the prologue and epilogue.
|
||||||
segment.data[0] = header_prologue[0];
|
segment.data[0] = header_prologue[0];
|
||||||
segment.data[1] = header_prologue[1];
|
segment.data[1] = header_prologue[1];
|
||||||
segment.data[2] = header_prologue[2];
|
segment.data[2] = header_prologue[2];
|
||||||
|
|
||||||
|
segment.data[346] = epilogue[0];
|
||||||
|
segment.data[347] = epilogue[1];
|
||||||
|
segment.data[348] = epilogue[2];
|
||||||
|
|
||||||
|
// Fill in byte values: the first 86 bytes contain shuffled
|
||||||
|
// and combined copies of the bottom two bits of the sector
|
||||||
|
// contents; the 256 bytes afterwards are the remaining
|
||||||
|
// six bits.
|
||||||
|
const uint8_t bit_shuffle[] = {0, 2, 1, 3};
|
||||||
|
for(std::size_t c = 0; c < 85; ++c) {
|
||||||
|
segment.data[3 + c] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
bit_shuffle[source[c]&3] |
|
||||||
|
(bit_shuffle[source[c + 85]&3] << 2) |
|
||||||
|
(bit_shuffle[source[c + 170]&3] << 4)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
segment.data[3 + 85] = bit_shuffle[source[255]&3];
|
||||||
|
|
||||||
|
for(std::size_t c = 0; c < 256; ++c) {
|
||||||
|
segment.data[3 + 85 + c] = source[c] >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclusive OR each byte with the one before it.
|
||||||
|
segment.data[344] = segment.data[343];
|
||||||
|
std::size_t location = 343;
|
||||||
|
while(location > 3) {
|
||||||
|
segment.data[location] ^= segment.data[location-1];
|
||||||
|
--location;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map six-bit values up to full bytes.
|
||||||
|
for(std::size_t c = 0; c < 343; ++c) {
|
||||||
|
segment.data[c] = six_and_two_mapping[segment.data[c]];
|
||||||
|
}
|
||||||
|
|
||||||
return segment;
|
return segment;
|
||||||
}
|
}
|
||||||
|
@ -20,22 +20,22 @@ namespace AppleGCR {
|
|||||||
/*!
|
/*!
|
||||||
@returns the eight-bit 13-sector GCR encoding for the low five bits of @c value.
|
@returns the eight-bit 13-sector GCR encoding for the low five bits of @c value.
|
||||||
*/
|
*/
|
||||||
unsigned int five_and_three_encoding_for_value(int value);
|
// unsigned int five_and_three_encoding_for_value(int value);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns the eight-bit 16-sector GCR encoding for the low six bits of @c value.
|
@returns the eight-bit 16-sector GCR encoding for the low six bits of @c value.
|
||||||
*/
|
*/
|
||||||
unsigned int six_and_two_encoding_for_value(int value);
|
// unsigned int six_and_two_encoding_for_value(int value);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
A block is defined to be five source bytes, which encodes to eight GCR bytes.
|
A block is defined to be five source bytes, which encodes to eight GCR bytes.
|
||||||
*/
|
*/
|
||||||
void encode_five_and_three_block(uint8_t *destination, uint8_t *source);
|
// void encode_five_and_three_block(uint8_t *destination, uint8_t *source);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
A block is defined to be three source bytes, which encodes to four GCR bytes.
|
A block is defined to be three source bytes, which encodes to four GCR bytes.
|
||||||
*/
|
*/
|
||||||
void encode_six_and_two_block(uint8_t *destination, uint8_t *source);
|
// void encode_six_and_two_block(uint8_t *destination, uint8_t *source);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns the four bit nibble for the five-bit GCR @c quintet if a valid GCR value; INT_MAX otherwise.
|
@returns the four bit nibble for the five-bit GCR @c quintet if a valid GCR value; INT_MAX otherwise.
|
||||||
@ -54,12 +54,16 @@ namespace AppleGCR {
|
|||||||
/// Describes the epilogue that ends both data sections and headers.
|
/// Describes the epilogue that ends both data sections and headers.
|
||||||
const uint8_t epilogue[3] = {0xde, 0xaa, 0xeb};
|
const uint8_t epilogue[3] = {0xde, 0xaa, 0xeb};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Produces the Apple-standard '4 and 4' per-sector header. This is the same
|
||||||
|
for both the 13- and 16-sector formats, and is 112 bits long.
|
||||||
|
*/
|
||||||
Storage::Disk::PCMSegment header(uint8_t volume, uint8_t track, uint8_t sector);
|
Storage::Disk::PCMSegment header(uint8_t volume, uint8_t track, uint8_t sector);
|
||||||
|
|
||||||
Storage::Disk::PCMSegment six_and_two_data(uint8_t *source);
|
Storage::Disk::PCMSegment six_and_two_data(const uint8_t *source);
|
||||||
Storage::Disk::PCMSegment six_and_two_sync(int length);
|
Storage::Disk::PCMSegment six_and_two_sync(int length);
|
||||||
|
|
||||||
Storage::Disk::PCMSegment five_and_three_data(uint8_t *source);
|
Storage::Disk::PCMSegment five_and_three_data(const uint8_t *source);
|
||||||
Storage::Disk::PCMSegment five_and_three_sync(int length);
|
Storage::Disk::PCMSegment five_and_three_sync(int length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user