mirror of
https://github.com/TomHarte/CLK.git
synced 2024-10-04 01:57:54 +00:00
Completes Mac GCR decoding and its associated test.
This commit is contained in:
parent
8f28b33342
commit
5a9f3cfc1e
@ -163,17 +163,19 @@
|
|||||||
uint8_t sector_plus_tags[524];
|
uint8_t sector_plus_tags[524];
|
||||||
|
|
||||||
// Provide tags plus a sector body that are just the sector number ad infinitum.
|
// Provide tags plus a sector body that are just the sector number ad infinitum.
|
||||||
memset(sector_plus_tags, sector_id, sizeof(sector_plus_tags));
|
for(size_t c = 0; c < sizeof(sector_plus_tags); ++c) {
|
||||||
|
sector_plus_tags[c] = uint8_t(sector_id + (c * 3));
|
||||||
|
}
|
||||||
|
|
||||||
// NB: sync lengths below are identical to those for
|
// NB: sync lengths below are identical to those for
|
||||||
// the Apple II, as I have no idea whatsoever what they
|
// the Apple II, as I have no idea whatsoever what they
|
||||||
// should be.
|
// should be.
|
||||||
|
|
||||||
segment += Storage::Encodings::AppleGCR::Macintosh::header(
|
segment += Storage::Encodings::AppleGCR::Macintosh::header(
|
||||||
format,
|
format ^ c,
|
||||||
track_id,
|
track_id - c,
|
||||||
sector_id,
|
sector_id,
|
||||||
is_side_two
|
is_side_two ^ (c & 1)
|
||||||
);
|
);
|
||||||
segment += Storage::Encodings::AppleGCR::six_and_two_sync(7);
|
segment += Storage::Encodings::AppleGCR::six_and_two_sync(7);
|
||||||
segment += Storage::Encodings::AppleGCR::Macintosh::data(sector_id, sector_plus_tags);
|
segment += Storage::Encodings::AppleGCR::Macintosh::data(sector_id, sector_plus_tags);
|
||||||
@ -183,8 +185,26 @@
|
|||||||
// Parse the prepared track to look for sectors.
|
// Parse the prepared track to look for sectors.
|
||||||
const auto decoded_sectors = Storage::Encodings::AppleGCR::sectors_from_segment(segment);
|
const auto decoded_sectors = Storage::Encodings::AppleGCR::sectors_from_segment(segment);
|
||||||
|
|
||||||
// Assert that all sectors fed in were found and correctly decoded.
|
// Assert that the proper number of sectors was found.
|
||||||
XCTAssertEqual(decoded_sectors.size(), 8);
|
XCTAssertEqual(decoded_sectors.size(), 8);
|
||||||
|
|
||||||
|
// Assert that the sector descriptions and contents are correct.
|
||||||
|
int sector = 0;
|
||||||
|
for(const auto &pair: decoded_sectors) {
|
||||||
|
XCTAssertFalse(pair.second.has_header_checksum_error);
|
||||||
|
XCTAssertFalse(pair.second.has_data_checksum_error);
|
||||||
|
|
||||||
|
XCTAssertEqual(pair.second.address.is_side_two, is_side_two ^ (sector & 1));
|
||||||
|
XCTAssertEqual(pair.second.address.format, format ^ sector);
|
||||||
|
XCTAssertEqual(pair.second.address.track, track_id - sector);
|
||||||
|
XCTAssertEqual(pair.second.address.sector, sector);
|
||||||
|
|
||||||
|
for(size_t c = 0; c < sizeof(pair.second.data.size()); ++c) {
|
||||||
|
XCTAssertEqual(pair.second.data[c], uint8_t(sector + (c * 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
++sector;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -24,8 +24,8 @@ struct Sector {
|
|||||||
struct {
|
struct {
|
||||||
/// For Apple II-type sectors, provides the volume number.
|
/// For Apple II-type sectors, provides the volume number.
|
||||||
uint_fast8_t volume = 0;
|
uint_fast8_t volume = 0;
|
||||||
/// For Macintosh-type sectors, provides the type from the sector header.
|
/// For Macintosh-type sectors, provides the format from the sector header.
|
||||||
uint_fast8_t type = 0;
|
uint_fast8_t format = 0;
|
||||||
};
|
};
|
||||||
uint_fast8_t track = 0;
|
uint_fast8_t track = 0;
|
||||||
uint_fast8_t sector = 0;
|
uint_fast8_t sector = 0;
|
||||||
|
@ -196,15 +196,67 @@ std::map<std::size_t, Sector> Storage::Encodings::AppleGCR::sectors_from_segment
|
|||||||
if(out_of_bounds) continue;
|
if(out_of_bounds) continue;
|
||||||
|
|
||||||
// Test the checksum.
|
// Test the checksum.
|
||||||
if(decoded_header[4] != (decoded_header[0] ^ decoded_header[1] ^ decoded_header[2] ^ decoded_header[3])) continue;
|
if(decoded_header[4] != (decoded_header[0] ^ decoded_header[1] ^ decoded_header[2] ^ decoded_header[3]))
|
||||||
|
sector->has_header_checksum_error = true;
|
||||||
|
|
||||||
// Decode the header.
|
// Decode the header.
|
||||||
sector->address.track = uint8_t(decoded_header[0] | ((decoded_header[2]&0x1f) << 6));
|
sector->address.track = uint8_t(decoded_header[0] | ((decoded_header[2]&0x1f) << 6));
|
||||||
sector->address.sector = decoded_header[1];
|
sector->address.sector = decoded_header[1];
|
||||||
sector->address.type = decoded_header[3];
|
sector->address.format = decoded_header[3];
|
||||||
sector->address.is_side_two = decoded_header[2] & 0x20;
|
sector->address.is_side_two = decoded_header[2] & 0x20;
|
||||||
|
|
||||||
// TODO: sector contents, naturally.
|
// Reverse the GCR encoding of the sector contents to get back to 6-bit data.
|
||||||
|
for(auto &c: sector->data) {
|
||||||
|
c = unmap_six_and_two(c);
|
||||||
|
if(c == 0xff) {
|
||||||
|
out_of_bounds = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(out_of_bounds) continue;
|
||||||
|
|
||||||
|
// The first byte in the sector is a repeat of the sector number; test it
|
||||||
|
// for correctness.
|
||||||
|
if(sector->data[0] != sector->address.sector) continue;
|
||||||
|
|
||||||
|
// Cf. the corresponding section of Encoder.cpp for logic below.
|
||||||
|
int checksum[3] = {0, 0, 0};
|
||||||
|
for(size_t c = 0; c < 175; ++c) {
|
||||||
|
// Calculate the rolling checcksum in order to decode the bytes.
|
||||||
|
checksum[0] = (checksum[0] << 1) | (checksum[0] >> 7);
|
||||||
|
|
||||||
|
// All offsets are +1 below, to skip the initial sector number duplicate.
|
||||||
|
const uint8_t top_bits = sector->data[1 + c*4];
|
||||||
|
|
||||||
|
// Decode first byte.
|
||||||
|
sector->data[0 + c * 3] = uint8_t((sector->data[2 + c*4] + ((top_bits & 0x30) << 2)) ^ checksum[0]);
|
||||||
|
checksum[2] += sector->data[0 + c * 3] + (checksum[0] >> 8);
|
||||||
|
|
||||||
|
// Decode second byte;
|
||||||
|
sector->data[1 + c * 3] = uint8_t((sector->data[3 + c*4] + ((top_bits & 0x0c) << 4)) ^ checksum[2]);
|
||||||
|
checksum[1] += sector->data[1 + c * 3] + (checksum[2] >> 8);
|
||||||
|
|
||||||
|
// Decode third byte, if there is one.
|
||||||
|
if(c != 174) {
|
||||||
|
sector->data[2 + c * 3] = uint8_t((sector->data[4 + c*4] + ((top_bits & 0x03) << 6)) ^ checksum[1]);
|
||||||
|
checksum[0] += sector->data[2 + c * 3] + (checksum[1] >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset carries.
|
||||||
|
checksum[0] &= 0xff;
|
||||||
|
checksum[1] &= 0xff;
|
||||||
|
checksum[2] &= 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the checksum.
|
||||||
|
if(
|
||||||
|
checksum[0] != uint8_t(sector->data[703] + ((sector->data[700] & 0x03) << 6)) ||
|
||||||
|
checksum[1] != uint8_t(sector->data[702] + ((sector->data[700] & 0x0c) << 4)) ||
|
||||||
|
checksum[2] != uint8_t(sector->data[701] + ((sector->data[700] & 0x30) << 2))
|
||||||
|
) sector->has_data_checksum_error = true;
|
||||||
|
|
||||||
|
// Chop to size, and that's that.
|
||||||
|
sector->data.resize(524);
|
||||||
|
|
||||||
// Add this sector to the map.
|
// Add this sector to the map.
|
||||||
sector->encoding = Sector::Encoding::Macintosh;
|
sector->encoding = Sector::Encoding::Macintosh;
|
||||||
|
Loading…
Reference in New Issue
Block a user